finish home page and start working on order preview page
parent
d1ac4080ca
commit
9a169ff77b
@ -0,0 +1,85 @@
|
|||||||
|
class Addresses {
|
||||||
|
String id;
|
||||||
|
String firstName;
|
||||||
|
String lastName;
|
||||||
|
String email;
|
||||||
|
String company;
|
||||||
|
int countryId;
|
||||||
|
String country;
|
||||||
|
String stateProvinceId;
|
||||||
|
String city;
|
||||||
|
String address1;
|
||||||
|
String address2;
|
||||||
|
String zipPostalCode;
|
||||||
|
String phoneNumber;
|
||||||
|
String faxNumber;
|
||||||
|
String customerAttributes;
|
||||||
|
String createdOnUtc;
|
||||||
|
String province;
|
||||||
|
String latLong;
|
||||||
|
|
||||||
|
Addresses(
|
||||||
|
{this.id,
|
||||||
|
this.firstName,
|
||||||
|
this.lastName,
|
||||||
|
this.email,
|
||||||
|
this.company,
|
||||||
|
this.countryId,
|
||||||
|
this.country,
|
||||||
|
this.stateProvinceId,
|
||||||
|
this.city,
|
||||||
|
this.address1,
|
||||||
|
this.address2,
|
||||||
|
this.zipPostalCode,
|
||||||
|
this.phoneNumber,
|
||||||
|
this.faxNumber,
|
||||||
|
this.customerAttributes,
|
||||||
|
this.createdOnUtc,
|
||||||
|
this.province,
|
||||||
|
this.latLong});
|
||||||
|
|
||||||
|
Addresses.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
firstName = json['first_name'];
|
||||||
|
lastName = json['last_name'];
|
||||||
|
email = json['email'];
|
||||||
|
company = json['company'];
|
||||||
|
countryId = json['country_id'];
|
||||||
|
country = json['country'];
|
||||||
|
stateProvinceId = json['state_province_id'];
|
||||||
|
city = json['city'];
|
||||||
|
address1 = json['address1'];
|
||||||
|
address2 = json['address2'];
|
||||||
|
zipPostalCode = json['zip_postal_code'];
|
||||||
|
phoneNumber = json['phone_number'];
|
||||||
|
faxNumber = json['fax_number'];
|
||||||
|
customerAttributes = json['customer_attributes'];
|
||||||
|
createdOnUtc = json['created_on_utc'];
|
||||||
|
province = json['province'];
|
||||||
|
latLong = json['lat_long'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['id'] = this.id;
|
||||||
|
data['first_name'] = this.firstName;
|
||||||
|
data['last_name'] = this.lastName;
|
||||||
|
data['email'] = this.email;
|
||||||
|
data['company'] = this.company;
|
||||||
|
data['country_id'] = this.countryId;
|
||||||
|
data['country'] = this.country;
|
||||||
|
data['state_province_id'] = this.stateProvinceId;
|
||||||
|
data['city'] = this.city;
|
||||||
|
data['address1'] = this.address1;
|
||||||
|
data['address2'] = this.address2;
|
||||||
|
data['zip_postal_code'] = this.zipPostalCode;
|
||||||
|
data['phone_number'] = this.phoneNumber;
|
||||||
|
data['fax_number'] = this.faxNumber;
|
||||||
|
data['customer_attributes'] = this.customerAttributes;
|
||||||
|
data['created_on_utc'] = this.createdOnUtc;
|
||||||
|
data['province'] = this.province;
|
||||||
|
data['lat_long'] = this.latLong;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import 'Customer.dart';
|
import '../pharmacies/Customer.dart';
|
||||||
|
|
||||||
class Reviews {
|
class Reviews {
|
||||||
int id;
|
int id;
|
@ -0,0 +1,29 @@
|
|||||||
|
import 'package:diplomaticquarterapp/config/config.dart';
|
||||||
|
import 'package:diplomaticquarterapp/core/model/pharmacies/Addresses.dart';
|
||||||
|
import 'package:diplomaticquarterapp/core/service/base_service.dart';
|
||||||
|
|
||||||
|
class OrderPreviewService extends BaseService{
|
||||||
|
bool isFinished = true;
|
||||||
|
bool hasError = false;
|
||||||
|
String errorMsg = '';
|
||||||
|
|
||||||
|
List<Addresses> addresses = List();
|
||||||
|
|
||||||
|
Future getBannerListList() async {
|
||||||
|
hasError = false;
|
||||||
|
try {
|
||||||
|
await baseAppClient.get(GET_CUSTOMERS_ADDRESSES,
|
||||||
|
onSuccess: (dynamic response, int statusCode) {
|
||||||
|
addresses.clear();
|
||||||
|
response['customers'][0]['addresses'].forEach((item) {
|
||||||
|
addresses.add(Addresses.fromJson(item));
|
||||||
|
});
|
||||||
|
}, onFailure: (String error, int statusCode) {
|
||||||
|
hasError = true;
|
||||||
|
super.error = error;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import 'package:diplomaticquarterapp/core/service/parmacyModule/order-preview-service.dart';
|
||||||
|
|
||||||
|
import '../../../locator.dart';
|
||||||
|
import '../base_view_model.dart';
|
||||||
|
|
||||||
|
class OrderPreviewViewModel extends BaseViewModel {
|
||||||
|
OrderPreviewService _orderService = locator<OrderPreviewService>();
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart';
|
||||||
|
import 'package:diplomaticquarterapp/pages/base/base_view.dart';
|
||||||
|
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
|
||||||
|
import 'package:diplomaticquarterapp/widgets/buttons/GestureIconButton.dart';
|
||||||
|
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class OrderPreviewPage extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BaseView<OrderPreviewViewModel>(
|
||||||
|
builder: (_, model, wi) => AppScaffold(
|
||||||
|
title: "Shopping Cart",
|
||||||
|
isShowAppBar: true,
|
||||||
|
isShowDecPage: false,
|
||||||
|
baseViewModel: model,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
body: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.all(10),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
GestureIconButton(
|
||||||
|
TranslationBase.of(context).deleteAllItems,
|
||||||
|
Icon(Icons.delete_outline_sharp, color: Colors.grey.shade800,),
|
||||||
|
onTap: () => {},
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
color: Colors.grey,
|
||||||
|
height: 20,
|
||||||
|
thickness: 1,
|
||||||
|
indent: 0,
|
||||||
|
endIndent: 0,
|
||||||
|
),
|
||||||
|
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
|||||||
|
import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart';
|
||||||
|
import 'package:diplomaticquarterapp/widgets/data_display/text.dart';
|
||||||
|
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ProductDetailScreen extends StatelessWidget {
|
||||||
|
final PharmacyProduct product;
|
||||||
|
|
||||||
|
ProductDetailScreen(this.product);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AppScaffold(
|
||||||
|
body: Center(
|
||||||
|
child: Texts("id = ${product.id}"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ProductOrderItem extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.delete_outline_sharp,
|
||||||
|
color: Colors.grey.shade800,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,146 @@
|
|||||||
|
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
|
||||||
|
import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart';
|
||||||
|
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
|
||||||
|
import 'package:diplomaticquarterapp/pages/pharmacies/screens/phramacy-product-detail-page.dart';
|
||||||
|
import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
|
||||||
|
import 'package:diplomaticquarterapp/widgets/data_display/text.dart';
|
||||||
|
import 'package:diplomaticquarterapp/widgets/others/StarRating.dart';
|
||||||
|
import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ProductTileItem extends StatelessWidget {
|
||||||
|
final AppSharedPreferences sharedPref = AppSharedPreferences();
|
||||||
|
final PharmacyProduct item;
|
||||||
|
|
||||||
|
ProductTileItem(this.item);
|
||||||
|
|
||||||
|
void productOnClick(BuildContext ctx) {
|
||||||
|
_saveLastVisitProducts();
|
||||||
|
Navigator.push(ctx, FadePage(page: ProductDetailScreen(item)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _saveLastVisitProducts() async {
|
||||||
|
String lastVisited = "";
|
||||||
|
bool isIdExist = false;
|
||||||
|
if (await this.sharedPref.getString(PHARMACY_LAST_VISITED_PRODUCTS) !=
|
||||||
|
null) {
|
||||||
|
lastVisited =
|
||||||
|
await this.sharedPref.getString(PHARMACY_LAST_VISITED_PRODUCTS);
|
||||||
|
lastVisited.split(",").forEach((id) {
|
||||||
|
if (id == item.id) {
|
||||||
|
isIdExist = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!isIdExist) {
|
||||||
|
if (lastVisited == "") {
|
||||||
|
// it means there is no lastVisited yet
|
||||||
|
lastVisited = "${item.id}";
|
||||||
|
} else {
|
||||||
|
// there is lastVisited id's and this product id is not found
|
||||||
|
lastVisited += ",${item.id}";
|
||||||
|
}
|
||||||
|
sharedPref.setString(PHARMACY_LAST_VISITED_PRODUCTS, lastVisited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
ProjectViewModel projectProvider = Provider.of(context);
|
||||||
|
return InkWell(
|
||||||
|
onTap: () => productOnClick(context),
|
||||||
|
splashColor: Theme.of(context).primaryColor,
|
||||||
|
child: Card(
|
||||||
|
elevation: 2,
|
||||||
|
shape: Border(right: BorderSide(color: Colors.grey.shade300, width: 1)),
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 4,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 0),
|
||||||
|
width: MediaQuery.of(context).size.width / 3,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.fromLTRB(0, 16, 0, 0),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Image.network(
|
||||||
|
item.images[0].src,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
height: 80,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: item.rxMessage != null
|
||||||
|
? MediaQuery.of(context).size.width / 5
|
||||||
|
: 0,
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(0xffb23838),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.only(topLeft: Radius.circular(6)),
|
||||||
|
),
|
||||||
|
child: Texts(
|
||||||
|
item.rxMessage != null ? item.rxMessage : "",
|
||||||
|
color: Colors.white,
|
||||||
|
regular: true,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.symmetric(
|
||||||
|
horizontal: 6,
|
||||||
|
vertical: 0,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Texts(
|
||||||
|
projectProvider.isArabic ? item.name : item.namen,
|
||||||
|
regular: true,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 4, bottom: 4),
|
||||||
|
child: Texts(
|
||||||
|
"SAR ${item.price}",
|
||||||
|
bold: true,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
StarRating(
|
||||||
|
totalAverage: item.approvedTotalReviews > 0
|
||||||
|
? (item.approvedRatingSum.toDouble() /
|
||||||
|
item.approvedTotalReviews.toDouble())
|
||||||
|
.toDouble()
|
||||||
|
: 0,
|
||||||
|
forceStars: true),
|
||||||
|
Texts(
|
||||||
|
"(${item.approvedTotalReviews})",
|
||||||
|
regular: true,
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import 'package:diplomaticquarterapp/core/model/pharmacy_module/Manufacturer.dart';
|
import 'package:diplomaticquarterapp/core/model/pharmacies/Manufacturer.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class ManufacturerItem extends StatelessWidget {
|
class ManufacturerItem extends StatelessWidget {
|
@ -1,107 +0,0 @@
|
|||||||
import 'package:diplomaticquarterapp/core/model/pharmacy_module/PharmacyProduct.dart';
|
|
||||||
import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart';
|
|
||||||
import 'package:diplomaticquarterapp/widgets/data_display/text.dart';
|
|
||||||
import 'package:diplomaticquarterapp/widgets/others/StarRating.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class ProductTileItem extends StatelessWidget {
|
|
||||||
final PharmacyProduct item;
|
|
||||||
|
|
||||||
ProductTileItem(this.item);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
ProjectViewModel projectProvider = Provider.of(context);
|
|
||||||
return Card(
|
|
||||||
elevation: 2,
|
|
||||||
shape: Border(right: BorderSide(color: Colors.grey.shade300, width: 1)),
|
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: 8,
|
|
||||||
vertical: 4,
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 0),
|
|
||||||
width: MediaQuery.of(context).size.width / 3,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.fromLTRB(0, 16, 0, 0),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Image.network(
|
|
||||||
item.images[0].src,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
height: 80,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
width: item.rxMessage != null
|
|
||||||
? MediaQuery.of(context).size.width / 5
|
|
||||||
: 0,
|
|
||||||
padding: EdgeInsets.all(4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Color(0xffb23838),
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.only(topLeft: Radius.circular(6)),
|
|
||||||
),
|
|
||||||
child: Texts(
|
|
||||||
item.rxMessage != null ? item.rxMessage : "",
|
|
||||||
color: Colors.white,
|
|
||||||
regular: true,
|
|
||||||
fontSize: 10,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.symmetric(
|
|
||||||
horizontal: 6,
|
|
||||||
vertical: 0,
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Texts(
|
|
||||||
projectProvider.isArabic ? item.name : item.namen,
|
|
||||||
regular: true,
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 4, bottom: 4),
|
|
||||||
child: Texts(
|
|
||||||
"SAR ${item.price}",
|
|
||||||
bold: true,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
StarRating(
|
|
||||||
totalAverage: item.approvedTotalReviews > 0
|
|
||||||
? (item.approvedRatingSum.toDouble() /
|
|
||||||
item.approvedTotalReviews.toDouble())
|
|
||||||
.toDouble()
|
|
||||||
: 0,
|
|
||||||
forceStars: true),
|
|
||||||
Texts(
|
|
||||||
"(${item.approvedTotalReviews})",
|
|
||||||
regular: true,
|
|
||||||
fontSize: 10,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,70 @@
|
|||||||
|
import 'package:diplomaticquarterapp/widgets/data_display/text.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class GestureIconButton extends StatefulWidget {
|
||||||
|
GestureIconButton(
|
||||||
|
this.label,
|
||||||
|
this.icon, {
|
||||||
|
Key key,
|
||||||
|
this.onTap,
|
||||||
|
this.backgroundColor,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
final Widget icon;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final Color backgroundColor;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_GestureIconButtonState createState() => _GestureIconButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GestureIconButtonState extends State<GestureIconButton> {
|
||||||
|
bool _buttonLongPress = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onLongPressStart: (_) =>
|
||||||
|
setState(() => _buttonLongPress = !_buttonLongPress),
|
||||||
|
onLongPressEnd: (_) =>
|
||||||
|
setState(() => _buttonLongPress = !_buttonLongPress),
|
||||||
|
child: Wrap(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: widget.backgroundColor != null
|
||||||
|
? widget.backgroundColor
|
||||||
|
: Colors.grey[200],
|
||||||
|
),
|
||||||
|
color: widget.backgroundColor != null
|
||||||
|
? widget.backgroundColor
|
||||||
|
: Colors.grey.shade200,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8))),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Container(
|
||||||
|
child: Expanded(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8.0),
|
||||||
|
child: widget.icon,
|
||||||
|
),
|
||||||
|
Texts(
|
||||||
|
widget.label,
|
||||||
|
color: _buttonLongPress ? Colors.white : Colors.black,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue