8/31/1
This commit is contained in:
@@ -3,14 +3,15 @@ import 'package:SEFER/env/env.dart';
|
||||
import 'package:SEFER/main.dart';
|
||||
|
||||
class AppLink {
|
||||
// static final String seferPaymentServer = Env.seferPaymentServer;
|
||||
static final String seferPaymentServer0 = Env.seferPaymentServer;
|
||||
static final String seferPaymentServer = '${Env.seferCairoServer}/ride';
|
||||
static final String seferAlexandriaServer = Env.seferAlexandriaServer;
|
||||
static final String seferCairoServer = Env.seferCairoServer;
|
||||
static final String seferGizaServer = Env.seferGizaServer;
|
||||
|
||||
static final String endPoint = box.read(BoxName.serverChosen);
|
||||
static final String server = endPoint;
|
||||
static final String server = Env.seferCairoServer;
|
||||
// static final String server = Env.serverPHP;
|
||||
|
||||
static String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
|
||||
static String llama = 'https://api.llama-api.com/chat/completions';
|
||||
@@ -86,9 +87,9 @@ class AppLink {
|
||||
static String addDriverpayment = "$ride/payment/add.php";
|
||||
static String addDriverPaymentPoints = "$ride/driverPayment/add.php";
|
||||
static String addPaymentTokenPassenger =
|
||||
"$ride/passengerWallet/addPaymentTokenPassenger.php";
|
||||
"$seferPaymentServer/passengerWallet/addPaymentTokenPassenger.php";
|
||||
static String addPaymentTokenDriver =
|
||||
"$ride/driverWallet/addPaymentToken.php";
|
||||
"$seferPaymentServer/driverWallet/addPaymentToken.php";
|
||||
static String getDriverPaymentPoints = "$ride/driverWallet/get.php";
|
||||
static String getDriverpaymentToday = "$ride/payment/get.php";
|
||||
static String getCountRide = "$ride/payment/getCountRide.php";
|
||||
|
||||
@@ -108,6 +108,7 @@ class RegisterController extends GetxController {
|
||||
var responseCheker = await CRUD()
|
||||
.post(link: AppLink.checkPhoneNumberISVerfiedPassenger, payload: {
|
||||
'phone_number': '+2${phoneController.text}',
|
||||
'email': box.read(BoxName.email),
|
||||
});
|
||||
if (responseCheker != 'failure') {
|
||||
var d = jsonDecode(responseCheker);
|
||||
@@ -194,7 +195,9 @@ class RegisterController extends GetxController {
|
||||
Get.offAll(const MapPagePassenger());
|
||||
}
|
||||
} else {
|
||||
Get.snackbar('Error'.tr, '', backgroundColor: Colors.redAccent);
|
||||
Get.snackbar(
|
||||
'Error'.tr, "The email or phone number is already registered.".tr,
|
||||
backgroundColor: Colors.redAccent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
lib/controller/firebase/access_token.dart
Normal file
50
lib/controller/firebase/access_token.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
import 'dart:convert';
|
||||
import 'package:googleapis_auth/auth_io.dart';
|
||||
|
||||
class AccessTokenManager {
|
||||
static final AccessTokenManager _instance = AccessTokenManager._internal();
|
||||
late final String serviceAccountJsonKey;
|
||||
AccessToken? _accessToken;
|
||||
DateTime? _expiryDate;
|
||||
|
||||
AccessTokenManager._internal();
|
||||
|
||||
factory AccessTokenManager(String jsonKey) {
|
||||
if (_instance._isServiceAccountKeyInitialized()) {
|
||||
// Prevent re-initialization
|
||||
return _instance;
|
||||
}
|
||||
_instance.serviceAccountJsonKey = jsonKey;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
bool _isServiceAccountKeyInitialized() {
|
||||
try {
|
||||
serviceAccountJsonKey; // Access to check if initialized
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getAccessToken() async {
|
||||
if (_accessToken != null && DateTime.now().isBefore(_expiryDate!)) {
|
||||
return _accessToken!.data;
|
||||
}
|
||||
try {
|
||||
final serviceAccountCredentials = ServiceAccountCredentials.fromJson(
|
||||
json.decode(serviceAccountJsonKey));
|
||||
final client = await clientViaServiceAccount(
|
||||
serviceAccountCredentials,
|
||||
['https://www.googleapis.com/auth/firebase.messaging'],
|
||||
);
|
||||
|
||||
_accessToken = client.credentials.accessToken;
|
||||
_expiryDate = client.credentials.accessToken.expiry;
|
||||
client.close();
|
||||
return _accessToken!.data;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to obtain access token');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:SEFER/env/env.dart';
|
||||
import 'package:SEFER/views/widgets/my_dialog.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:googleapis_auth/auth_io.dart';
|
||||
import 'package:googleapis_auth/googleapis_auth.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:SEFER/controller/functions/toast.dart';
|
||||
import 'package:SEFER/views/widgets/elevated_btn.dart';
|
||||
@@ -21,6 +24,7 @@ import '../../views/home/profile/promos_passenger_page.dart';
|
||||
import '../auth/google_sign.dart';
|
||||
import '../functions/audio_record1.dart';
|
||||
import '../home/map_passenger_controller.dart';
|
||||
import 'access_token.dart';
|
||||
import 'local_notification.dart';
|
||||
|
||||
class FirebaseMessagesController extends GetxController {
|
||||
@@ -189,7 +193,7 @@ class FirebaseMessagesController extends GetxController {
|
||||
Get.back();
|
||||
Get.defaultDialog(
|
||||
title: "The driver canceled your ride.".tr,
|
||||
middleText: "We will look for a new driver.\nPlease wait.".tr,
|
||||
middleText: "We will look for a new driver.\\nPlease wait.".tr,
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Ok'.tr,
|
||||
onPressed: () async {
|
||||
@@ -525,84 +529,217 @@ class FirebaseMessagesController extends GetxController {
|
||||
void sendNotificationToAnyWithoutData(
|
||||
String title, String body, String token, String tone) async {
|
||||
try {
|
||||
String serviceAccountKeyJson = '''{
|
||||
"type": "service_account",
|
||||
"project_id": "ride-b1bd8",
|
||||
"private_key_id": "75e817c0b902db2ef35edf2c2bd159dec1f13249",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0zH9TQGDQHUv3\\na3/JAD1UKPwAp3wNKT0a6fxiIzjI3JxQWI30QvZCcfl6CdMhIcydX1ncSaYTcEeC\\n/AdPVCPkqyJx1YIGGg6P/mRzCWeaN8fsp6z250m5vcObDCZc3dbJEkepbep+6FPY\\n21m3KO+AHh1glgsTGZOTm5xiU8NGXpdk2QEh8wpiIIlR/HuKwVw9g8urNe3Sno+U\\nDm3z37iFqvZdmpqO8aWTJu6beb3hsREK9XK2I9JqC2JUwiGQRo3idOvPP6hkqrWx\\nKSX96vglQFYfakvJdDp2ZATOlpBYPMtS/IWhJ985u58TSS+Kl8qpnpaZBSxgJirf\\nhWzhnKLfAgMBAAECggEAJP785SePGhS7ZN6ltspm+l+hSjYFrPWFCxq+rlQ1YkHZ\\nC9l+RqKSFhOkiPmQI2s4wbXl3kFxLHHlFNoi/q2wKQBmGb8TQfnRJpjjNHGA61Ev\\n0Ue7/6qPvVb9B2MsLw/FxKiTFPuMG3bgKR9pbSFuJLYoaW7zqITOhVnYphGTqwAY\\nBVVcvISSLvELDmH9VZcv/9DVqVlqbbESHWh1Z4W6XGPoEqeDH/upNTyQQ/46Msgm\\nTGE6VqLHpWuSf6SqHp+r0Y0lI3vIPM1vz5FAJDJbOE/enHa0fSup0OHSMxl0HVMn\\nnO1yrGF3vsIPOej5HKr5d71bEIckzk73/yjNC1/mDQKBgQD7RtUvc9omsSsFMJ6e\\nBASAn6Dktx/QY/XNJjFzHQj69cywLDe5t5AL2gUi3phQ2oqB5XJdwnd5bTIEPEPZ\\nDOuOai2802p6FJk6kjmZAMVGx5JtXBH+vs6jrmQQSMiKbjwN1TT6xIWakvLOonUi\\nX6ZvjYYjU/E0YJU3jSiXWEr76wKBgQD5Zn4SouJ6BCDZMbausJVMBkk3qxsYooip\\np89WakC6e7AZinpkRcqjGGV9GOvc8crJs6fyXAA9ORepGP47Mc0ZrDssOkstznsM\\npr8R0S6MKwEZaT9ixOHdOcLZ47ps+JzA2Wr4KN2OvFHksUkB/46ATD1j9WZVgB8M\\namsYp/Y73QKBgHOo+PvsoZ9psVmkNX6abtAdqdtdB0HOoRea2uwXk0ig12TIFaZg\\nfedWpUKVnxqoXVTJHklV99RmlL0qWDiSH+LfsMnXro0e6iDxqZ1po2Se/CFmXcoa\\nXdctsFVmixhdATuExewfhTfPKABA+xWlXWC/jdy5CK+JPWXijaqMM4edAoGAE5Bj\\nsWiPpYyvWvpYX0nA3G7dzX0hqgQN/mkIjbnWDArp3IcNZNJIvBSM2Yxb7EAXbU0n\\njo6DAkp5Pa2VO+WDNlFZbvW/sf8xjeOCt44WPa6d7nVgIIpbQXRngZoopKW3/jTP\\n/FmQT8McFXmGxZ5belsAsdetSGW9icbLUerTGQ0CgYEAmf/G8Ag3XxmqTXvvHuv2\\n14OP7WnrVqkEMnydrftEwn4peXd/Lz+/GYX5Zc4ZoNgbN8IvZ5z0+OmRsallsbiW\\nBw0/tc68CjzxXOvReWxDluUopqWVGj5tlGqE5xUDku9SWJSxbkiQ3rqutzBdPXpr\\noqHwPyDrmK/Zgqn+uiIm4Ck=\\n-----END PRIVATE KEY-----\\n",
|
||||
"client_email": "firebase-adminsdk-o2wqi@ride-b1bd8.iam.gserviceaccount.com",
|
||||
"client_id": "111210077025005706623",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o2wqi%40ride-b1bd8.iam.gserviceaccount.com",
|
||||
"universe_domain": "googleapis.com"
|
||||
}
|
||||
'''; // As defined above
|
||||
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
// Log.print('accessToken: ${accessToken}');
|
||||
|
||||
// Send the notification
|
||||
final response = await http.post(
|
||||
Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'key=${AK.serverAPI}'
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'notification': <String, dynamic>{
|
||||
'title': title,
|
||||
'body': body,
|
||||
'sound': tone
|
||||
'message': {
|
||||
'token': token,
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': body,
|
||||
},
|
||||
'android': {
|
||||
'notification': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
'apns': {
|
||||
'payload': {
|
||||
'aps': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'data': <String, dynamic>{
|
||||
'click_action': 'FLUTTER_NOTIFICATION_CLICK',
|
||||
'id': '1',
|
||||
'status': 'done'
|
||||
},
|
||||
'priority': 'high',
|
||||
'to': token,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
// Notification sent successfully
|
||||
print(
|
||||
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
print('Response body: ${response.body}');
|
||||
} else {
|
||||
// Handle error response
|
||||
'Failed to send notification. Status code: ${response.statusCode}';
|
||||
print(
|
||||
'Failed to send notification. Status code: ${response.statusCode}');
|
||||
print('Response body: ${response.body}');
|
||||
}
|
||||
} catch (e) {
|
||||
// Handle other exceptions
|
||||
print('Error sending notification: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void sendNotificationToDriverMAP(String title, String body, String token,
|
||||
List<String> data, String tone) async {
|
||||
// void sendNotificationToDriverMAP(String title, String body, String token,
|
||||
// List<String> data, String tone) async {
|
||||
// try {
|
||||
// final response = await http.post(
|
||||
// // Uri.parse(
|
||||
// // 'https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send'),
|
||||
// Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
||||
// headers: <String, String>{
|
||||
// 'Content-Type': 'application/json',
|
||||
// // 'Authorization': 'Bearer 104815009508844392546'
|
||||
// 'Authorization': 'key=${AK.serverAPI}'
|
||||
// },
|
||||
// body: jsonEncode({
|
||||
// 'notification': <String, dynamic>{
|
||||
// 'title': title,
|
||||
// 'body': body,
|
||||
// 'sound': tone
|
||||
// },
|
||||
// 'data': {
|
||||
// 'DriverList': data,
|
||||
// },
|
||||
// 'priority': 'high',
|
||||
// 'to': token,
|
||||
// }),
|
||||
// );
|
||||
|
||||
// if (response.statusCode == 200) {
|
||||
// Log.print(
|
||||
// 'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
// Log.print('Response body: ${response.body}');
|
||||
// } else {
|
||||
// Log.print(
|
||||
// 'Failed to send notification. Status code: ${response.statusCode}');
|
||||
// Log.print('Response body: ${response.body}');
|
||||
// }
|
||||
// } catch (e) {
|
||||
// Log.print('Error sending notification: $e');
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> sendNotificationToDriverMAP(String title, String body,
|
||||
String token, List<String> data, String tone) async {
|
||||
try {
|
||||
String serviceAccountKeyJson = '''{
|
||||
"type": "service_account",
|
||||
"project_id": "ride-b1bd8",
|
||||
"private_key_id": "75e817c0b902db2ef35edf2c2bd159dec1f13249",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0zH9TQGDQHUv3\\na3/JAD1UKPwAp3wNKT0a6fxiIzjI3JxQWI30QvZCcfl6CdMhIcydX1ncSaYTcEeC\\n/AdPVCPkqyJx1YIGGg6P/mRzCWeaN8fsp6z250m5vcObDCZc3dbJEkepbep+6FPY\\n21m3KO+AHh1glgsTGZOTm5xiU8NGXpdk2QEh8wpiIIlR/HuKwVw9g8urNe3Sno+U\\nDm3z37iFqvZdmpqO8aWTJu6beb3hsREK9XK2I9JqC2JUwiGQRo3idOvPP6hkqrWx\\nKSX96vglQFYfakvJdDp2ZATOlpBYPMtS/IWhJ985u58TSS+Kl8qpnpaZBSxgJirf\\nhWzhnKLfAgMBAAECggEAJP785SePGhS7ZN6ltspm+l+hSjYFrPWFCxq+rlQ1YkHZ\\nC9l+RqKSFhOkiPmQI2s4wbXl3kFxLHHlFNoi/q2wKQBmGb8TQfnRJpjjNHGA61Ev\\n0Ue7/6qPvVb9B2MsLw/FxKiTFPuMG3bgKR9pbSFuJLYoaW7zqITOhVnYphGTqwAY\\nBVVcvISSLvELDmH9VZcv/9DVqVlqbbESHWh1Z4W6XGPoEqeDH/upNTyQQ/46Msgm\\nTGE6VqLHpWuSf6SqHp+r0Y0lI3vIPM1vz5FAJDJbOE/enHa0fSup0OHSMxl0HVMn\\nnO1yrGF3vsIPOej5HKr5d71bEIckzk73/yjNC1/mDQKBgQD7RtUvc9omsSsFMJ6e\\nBASAn6Dktx/QY/XNJjFzHQj69cywLDe5t5AL2gUi3phQ2oqB5XJdwnd5bTIEPEPZ\\nDOuOai2802p6FJk6kjmZAMVGx5JtXBH+vs6jrmQQSMiKbjwN1TT6xIWakvLOonUi\\nX6ZvjYYjU/E0YJU3jSiXWEr76wKBgQD5Zn4SouJ6BCDZMbausJVMBkk3qxsYooip\\np89WakC6e7AZinpkRcqjGGV9GOvc8crJs6fyXAA9ORepGP47Mc0ZrDssOkstznsM\\npr8R0S6MKwEZaT9ixOHdOcLZ47ps+JzA2Wr4KN2OvFHksUkB/46ATD1j9WZVgB8M\\namsYp/Y73QKBgHOo+PvsoZ9psVmkNX6abtAdqdtdB0HOoRea2uwXk0ig12TIFaZg\\nfedWpUKVnxqoXVTJHklV99RmlL0qWDiSH+LfsMnXro0e6iDxqZ1po2Se/CFmXcoa\\nXdctsFVmixhdATuExewfhTfPKABA+xWlXWC/jdy5CK+JPWXijaqMM4edAoGAE5Bj\\nsWiPpYyvWvpYX0nA3G7dzX0hqgQN/mkIjbnWDArp3IcNZNJIvBSM2Yxb7EAXbU0n\\njo6DAkp5Pa2VO+WDNlFZbvW/sf8xjeOCt44WPa6d7nVgIIpbQXRngZoopKW3/jTP\\n/FmQT8McFXmGxZ5belsAsdetSGW9icbLUerTGQ0CgYEAmf/G8Ag3XxmqTXvvHuv2\\n14OP7WnrVqkEMnydrftEwn4peXd/Lz+/GYX5Zc4ZoNgbN8IvZ5z0+OmRsallsbiW\\nBw0/tc68CjzxXOvReWxDluUopqWVGj5tlGqE5xUDku9SWJSxbkiQ3rqutzBdPXpr\\noqHwPyDrmK/Zgqn+uiIm4Ck=\\n-----END PRIVATE KEY-----\\n",
|
||||
"client_email": "firebase-adminsdk-o2wqi@ride-b1bd8.iam.gserviceaccount.com",
|
||||
"client_id": "111210077025005706623",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o2wqi%40ride-b1bd8.iam.gserviceaccount.com",
|
||||
"universe_domain": "googleapis.com"
|
||||
}
|
||||
'''; // As defined above
|
||||
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
Log.print('accessToken: ${accessToken}');
|
||||
|
||||
// Send the notification
|
||||
final response = await http.post(
|
||||
Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'key=${AK.serverAPI}'
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'notification': <String, dynamic>{
|
||||
'title': title,
|
||||
'body': body,
|
||||
'sound': tone
|
||||
'message': {
|
||||
'token': token,
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': body,
|
||||
},
|
||||
'data': {
|
||||
'DriverList': jsonEncode(data),
|
||||
},
|
||||
'android': {
|
||||
'notification': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
'apns': {
|
||||
'payload': {
|
||||
'aps': {
|
||||
'sound': tone,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'data': {
|
||||
'DriverList': data,
|
||||
},
|
||||
'priority': 'high',
|
||||
'to': token,
|
||||
}),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
Log.print(
|
||||
print(
|
||||
'Notification sent successfully. Status code: ${response.statusCode}');
|
||||
Log.print('Response body: ${response.body}');
|
||||
print('Response body: ${response.body}');
|
||||
} else {
|
||||
Log.print(
|
||||
print(
|
||||
'Failed to send notification. Status code: ${response.statusCode}');
|
||||
Log.print('Response body: ${response.body}');
|
||||
print('Response body: ${response.body}');
|
||||
}
|
||||
} catch (e) {
|
||||
Log.print('Error sending notification: $e');
|
||||
print('Error sending notification: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void sendNotificationToDriverMapPolyline(String title, String body,
|
||||
String token, List<String> data, String polylineJson) async {
|
||||
try {
|
||||
String serviceAccountKeyJson = '''{
|
||||
"type": "service_account",
|
||||
"project_id": "ride-b1bd8",
|
||||
"private_key_id": "75e817c0b902db2ef35edf2c2bd159dec1f13249",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0zH9TQGDQHUv3\\na3/JAD1UKPwAp3wNKT0a6fxiIzjI3JxQWI30QvZCcfl6CdMhIcydX1ncSaYTcEeC\\n/AdPVCPkqyJx1YIGGg6P/mRzCWeaN8fsp6z250m5vcObDCZc3dbJEkepbep+6FPY\\n21m3KO+AHh1glgsTGZOTm5xiU8NGXpdk2QEh8wpiIIlR/HuKwVw9g8urNe3Sno+U\\nDm3z37iFqvZdmpqO8aWTJu6beb3hsREK9XK2I9JqC2JUwiGQRo3idOvPP6hkqrWx\\nKSX96vglQFYfakvJdDp2ZATOlpBYPMtS/IWhJ985u58TSS+Kl8qpnpaZBSxgJirf\\nhWzhnKLfAgMBAAECggEAJP785SePGhS7ZN6ltspm+l+hSjYFrPWFCxq+rlQ1YkHZ\\nC9l+RqKSFhOkiPmQI2s4wbXl3kFxLHHlFNoi/q2wKQBmGb8TQfnRJpjjNHGA61Ev\\n0Ue7/6qPvVb9B2MsLw/FxKiTFPuMG3bgKR9pbSFuJLYoaW7zqITOhVnYphGTqwAY\\nBVVcvISSLvELDmH9VZcv/9DVqVlqbbESHWh1Z4W6XGPoEqeDH/upNTyQQ/46Msgm\\nTGE6VqLHpWuSf6SqHp+r0Y0lI3vIPM1vz5FAJDJbOE/enHa0fSup0OHSMxl0HVMn\\nnO1yrGF3vsIPOej5HKr5d71bEIckzk73/yjNC1/mDQKBgQD7RtUvc9omsSsFMJ6e\\nBASAn6Dktx/QY/XNJjFzHQj69cywLDe5t5AL2gUi3phQ2oqB5XJdwnd5bTIEPEPZ\\nDOuOai2802p6FJk6kjmZAMVGx5JtXBH+vs6jrmQQSMiKbjwN1TT6xIWakvLOonUi\\nX6ZvjYYjU/E0YJU3jSiXWEr76wKBgQD5Zn4SouJ6BCDZMbausJVMBkk3qxsYooip\\np89WakC6e7AZinpkRcqjGGV9GOvc8crJs6fyXAA9ORepGP47Mc0ZrDssOkstznsM\\npr8R0S6MKwEZaT9ixOHdOcLZ47ps+JzA2Wr4KN2OvFHksUkB/46ATD1j9WZVgB8M\\namsYp/Y73QKBgHOo+PvsoZ9psVmkNX6abtAdqdtdB0HOoRea2uwXk0ig12TIFaZg\\nfedWpUKVnxqoXVTJHklV99RmlL0qWDiSH+LfsMnXro0e6iDxqZ1po2Se/CFmXcoa\\nXdctsFVmixhdATuExewfhTfPKABA+xWlXWC/jdy5CK+JPWXijaqMM4edAoGAE5Bj\\nsWiPpYyvWvpYX0nA3G7dzX0hqgQN/mkIjbnWDArp3IcNZNJIvBSM2Yxb7EAXbU0n\\njo6DAkp5Pa2VO+WDNlFZbvW/sf8xjeOCt44WPa6d7nVgIIpbQXRngZoopKW3/jTP\\n/FmQT8McFXmGxZ5belsAsdetSGW9icbLUerTGQ0CgYEAmf/G8Ag3XxmqTXvvHuv2\\n14OP7WnrVqkEMnydrftEwn4peXd/Lz+/GYX5Zc4ZoNgbN8IvZ5z0+OmRsallsbiW\\nBw0/tc68CjzxXOvReWxDluUopqWVGj5tlGqE5xUDku9SWJSxbkiQ3rqutzBdPXpr\\noqHwPyDrmK/Zgqn+uiIm4Ck=\\n-----END PRIVATE KEY-----\\n",
|
||||
"client_email": "firebase-adminsdk-o2wqi@ride-b1bd8.iam.gserviceaccount.com",
|
||||
"client_id": "111210077025005706623",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-o2wqi%40ride-b1bd8.iam.gserviceaccount.com",
|
||||
"universe_domain": "googleapis.com"
|
||||
}
|
||||
'''; // As defined above
|
||||
|
||||
// Initialize AccessTokenManager
|
||||
final accessTokenManager = AccessTokenManager(serviceAccountKeyJson);
|
||||
|
||||
// Obtain an OAuth 2.0 access token
|
||||
final accessToken = await accessTokenManager.getAccessToken();
|
||||
|
||||
// Send the notification
|
||||
final response = await http.post(
|
||||
Uri.parse('https://fcm.googleapis.com/fcm/send'),
|
||||
Uri.parse(
|
||||
'https://fcm.googleapis.com/v1/projects/ride-b1bd8/messages:send'),
|
||||
headers: <String, String>{
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'key=${AK.serverAPI}'
|
||||
'Authorization': 'Bearer $accessToken',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'notification': <String, dynamic>{
|
||||
|
||||
@@ -234,7 +234,6 @@ class CRUD {
|
||||
},
|
||||
);
|
||||
Log.print('payload: ${payload}');
|
||||
// print(response.request);
|
||||
Log.print('response.request: ${response.request}');
|
||||
Log.print('response.body: ${response.body}');
|
||||
var jsonData = jsonDecode(response.body);
|
||||
|
||||
@@ -1016,11 +1016,11 @@ class MapPassengerController extends GetxController {
|
||||
late String make = '';
|
||||
late String licensePlate = '';
|
||||
confirmRideForFirstDriver() async {
|
||||
// startCarLocationSearch(box.read(BoxName.carType));
|
||||
await getCarsLocationByPassengerAndReloadMarker(
|
||||
box.read(BoxName.carType), 7000);
|
||||
startCarLocationSearch(box.read(BoxName.carType));
|
||||
// await getCarsLocationByPassengerAndReloadMarker(
|
||||
// box.read(BoxName.carType), 7000);
|
||||
await getNearestDriverByPassengerLocationAPIGOOGLE();
|
||||
|
||||
Log.print('dataCarsLocationByPassenger: ${dataCarsLocationByPassenger}');
|
||||
if (dataCarsLocationByPassenger != 'failure' ||
|
||||
dataCarsLocationByPassenger != null) {
|
||||
driverToken =
|
||||
@@ -1132,50 +1132,50 @@ class MapPassengerController extends GetxController {
|
||||
Log.print(
|
||||
'body: ${dataCarsLocationByPassenger['message'][carsOrder]['token']}');
|
||||
});
|
||||
CRUD().post(
|
||||
link: '${AppLink.seferAlexandriaServer}/ride/rides/add.php',
|
||||
payload: {
|
||||
"start_location": //'${data[0]['start_address']}',
|
||||
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
||||
"end_location": //'${data[0]['end_address']}',
|
||||
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
||||
"date": DateTime.now().toString(),
|
||||
"time": DateTime.now().toString(),
|
||||
"endtime": durationToAdd.toString(),
|
||||
"price": totalPassenger.toStringAsFixed(2),
|
||||
"passenger_id": box.read(BoxName.passengerID).toString(),
|
||||
"driver_id": dataCarsLocationByPassenger['message'][carsOrder]
|
||||
['driver_id']
|
||||
.toString(),
|
||||
"status": "waiting",
|
||||
'carType': box.read(BoxName.carType),
|
||||
"price_for_driver": totalPassenger.toString(),
|
||||
"price_for_passenger": totalME.toString(),
|
||||
"distance": distance.toString(),
|
||||
"paymentMethod": paymentController.isWalletChecked.toString(),
|
||||
});
|
||||
CRUD().post(
|
||||
link: '${AppLink.seferGizaServer}/ride/rides/add.php',
|
||||
payload: {
|
||||
"start_location": //'${data[0]['start_address']}',
|
||||
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
||||
"end_location": //'${data[0]['end_address']}',
|
||||
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
||||
"date": DateTime.now().toString(),
|
||||
"time": DateTime.now().toString(),
|
||||
"endtime": durationToAdd.toString(),
|
||||
"price": totalPassenger.toStringAsFixed(2),
|
||||
"passenger_id": box.read(BoxName.passengerID).toString(),
|
||||
"driver_id": dataCarsLocationByPassenger['message'][carsOrder]
|
||||
['driver_id']
|
||||
.toString(),
|
||||
"status": "waiting",
|
||||
'carType': box.read(BoxName.carType),
|
||||
"price_for_driver": totalPassenger.toString(),
|
||||
"price_for_passenger": totalME.toString(),
|
||||
"distance": distance.toString(),
|
||||
"paymentMethod": paymentController.isWalletChecked.toString(),
|
||||
});
|
||||
// CRUD().post(
|
||||
// link: '${AppLink.seferAlexandriaServer}/ride/rides/add.php',
|
||||
// payload: {
|
||||
// "start_location": //'${data[0]['start_address']}',
|
||||
// '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
||||
// "end_location": //'${data[0]['end_address']}',
|
||||
// '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
||||
// "date": DateTime.now().toString(),
|
||||
// "time": DateTime.now().toString(),
|
||||
// "endtime": durationToAdd.toString(),
|
||||
// "price": totalPassenger.toStringAsFixed(2),
|
||||
// "passenger_id": box.read(BoxName.passengerID).toString(),
|
||||
// "driver_id": dataCarsLocationByPassenger['message'][carsOrder]
|
||||
// ['driver_id']
|
||||
// .toString(),
|
||||
// "status": "waiting",
|
||||
// 'carType': box.read(BoxName.carType),
|
||||
// "price_for_driver": totalPassenger.toString(),
|
||||
// "price_for_passenger": totalME.toString(),
|
||||
// "distance": distance.toString(),
|
||||
// "paymentMethod": paymentController.isWalletChecked.toString(),
|
||||
// });
|
||||
// CRUD().post(
|
||||
// link: '${AppLink.seferGizaServer}/ride/rides/add.php',
|
||||
// payload: {
|
||||
// "start_location": //'${data[0]['start_address']}',
|
||||
// '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
||||
// "end_location": //'${data[0]['end_address']}',
|
||||
// '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
||||
// "date": DateTime.now().toString(),
|
||||
// "time": DateTime.now().toString(),
|
||||
// "endtime": durationToAdd.toString(),
|
||||
// "price": totalPassenger.toStringAsFixed(2),
|
||||
// "passenger_id": box.read(BoxName.passengerID).toString(),
|
||||
// "driver_id": dataCarsLocationByPassenger['message'][carsOrder]
|
||||
// ['driver_id']
|
||||
// .toString(),
|
||||
// "status": "waiting",
|
||||
// 'carType': box.read(BoxName.carType),
|
||||
// "price_for_driver": totalPassenger.toString(),
|
||||
// "price_for_passenger": totalME.toString(),
|
||||
// "distance": distance.toString(),
|
||||
// "paymentMethod": paymentController.isWalletChecked.toString(),
|
||||
// });
|
||||
|
||||
delayAndFetchRideStatus(rideId);
|
||||
if (shouldFetch == false) {
|
||||
@@ -1202,67 +1202,79 @@ class MapPassengerController extends GetxController {
|
||||
|
||||
bool isDriversTokensSend = false;
|
||||
confirmRideForAllDriverAvailable() async {
|
||||
driversToken.remove(driverToken);
|
||||
PaymentController paymentController = Get.find<PaymentController>();
|
||||
rideConfirm = true;
|
||||
shouldFetch = true;
|
||||
isBottomSheetShown = false;
|
||||
timeToPassengerFromDriverAfterApplied = 60;
|
||||
await getCarsLocationByPassengerAndReloadMarker(
|
||||
box.read(BoxName.carType), 7000);
|
||||
if (dataCarsLocationByPassenger != 'failure') {
|
||||
driversToken.remove(driverToken);
|
||||
PaymentController paymentController = Get.find<PaymentController>();
|
||||
rideConfirm = true;
|
||||
shouldFetch = true;
|
||||
isBottomSheetShown = false;
|
||||
timeToPassengerFromDriverAfterApplied = 60;
|
||||
|
||||
List<String> body = [
|
||||
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
||||
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
||||
totalPassenger.toStringAsFixed(2),
|
||||
totalDriver.toStringAsFixed(2),
|
||||
durationToRide.toString(),
|
||||
distance.toStringAsFixed(2),
|
||||
dataCarsLocationByPassenger['message'][carsOrder]['driver_id'].toString(),
|
||||
box.read(BoxName.passengerID).toString(),
|
||||
box.read(BoxName.name).toString(),
|
||||
box.read(BoxName.tokenFCM).toString(),
|
||||
box.read(BoxName.phone).toString(),
|
||||
durationByPassenger.toString(),
|
||||
distanceByPassenger.toString(),
|
||||
paymentController.isWalletChecked.toString(),
|
||||
dataCarsLocationByPassenger['message'][carsOrder]['token'].toString(),
|
||||
durationToPassenger.toString(),
|
||||
rideId,
|
||||
rideTimerBegin.toString(),
|
||||
dataCarsLocationByPassenger['message'][carsOrder]['driver_id'].toString(),
|
||||
durationToRide.toString(),
|
||||
Get.find<WayPointController>().wayPoints.length > 1
|
||||
? 'haveSteps'
|
||||
: 'startEnd',
|
||||
placesCoordinate[0],
|
||||
placesCoordinate[1],
|
||||
placesCoordinate[2],
|
||||
placesCoordinate[3],
|
||||
placesCoordinate[4],
|
||||
costForDriver.toStringAsFixed(2),
|
||||
double.parse(box.read(BoxName.passengerWalletTotal)) < 0
|
||||
? double.parse(box.read(BoxName.passengerWalletTotal))
|
||||
.toStringAsFixed(2)
|
||||
: '0',
|
||||
box.read(BoxName.email).toString(),
|
||||
startNameAddress,
|
||||
endNameAddress,
|
||||
box.read(BoxName.carType),
|
||||
kazan.toStringAsFixed(0),
|
||||
passengerRate.toStringAsFixed(2),
|
||||
];
|
||||
Log.print('body: ${body}');
|
||||
for (var i = 1; i < driversToken.length; i++) {
|
||||
FirebaseMessagesController().sendNotificationToDriverMapPolyline(
|
||||
'OrderSpeed',
|
||||
rideId.toString(),
|
||||
driversToken[i],
|
||||
body,
|
||||
polylineCoordinates.toString());
|
||||
List<String> body = [
|
||||
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
|
||||
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
|
||||
totalPassenger.toStringAsFixed(2),
|
||||
totalDriver.toStringAsFixed(2),
|
||||
durationToRide.toString(),
|
||||
distance.toStringAsFixed(2),
|
||||
dataCarsLocationByPassenger['message'][carsOrder]['driver_id']
|
||||
.toString(),
|
||||
box.read(BoxName.passengerID).toString(),
|
||||
box.read(BoxName.name).toString(),
|
||||
box.read(BoxName.tokenFCM).toString(),
|
||||
box.read(BoxName.phone).toString(),
|
||||
durationByPassenger.toString(),
|
||||
distanceByPassenger.toString(),
|
||||
paymentController.isWalletChecked.toString(),
|
||||
dataCarsLocationByPassenger['message'][carsOrder]['token'].toString(),
|
||||
durationToPassenger.toString(),
|
||||
rideId,
|
||||
rideTimerBegin.toString(),
|
||||
dataCarsLocationByPassenger['message'][carsOrder]['driver_id']
|
||||
.toString(),
|
||||
durationToRide.toString(),
|
||||
Get.find<WayPointController>().wayPoints.length > 1
|
||||
? 'haveSteps'
|
||||
: 'startEnd',
|
||||
placesCoordinate[0],
|
||||
placesCoordinate[1],
|
||||
placesCoordinate[2],
|
||||
placesCoordinate[3],
|
||||
placesCoordinate[4],
|
||||
costForDriver.toStringAsFixed(2),
|
||||
double.parse(box.read(BoxName.passengerWalletTotal)) < 0
|
||||
? double.parse(box.read(BoxName.passengerWalletTotal))
|
||||
.toStringAsFixed(2)
|
||||
: '0',
|
||||
box.read(BoxName.email).toString(),
|
||||
startNameAddress,
|
||||
endNameAddress,
|
||||
box.read(BoxName.carType),
|
||||
kazan.toStringAsFixed(0),
|
||||
passengerRate.toStringAsFixed(2),
|
||||
];
|
||||
Log.print('body: ${body}');
|
||||
for (var i = 1; i < driversToken.length; i++) {
|
||||
FirebaseMessagesController().sendNotificationToDriverMapPolyline(
|
||||
'OrderSpeed',
|
||||
rideId.toString(),
|
||||
driversToken[i],
|
||||
body,
|
||||
polylineCoordinates.toString());
|
||||
}
|
||||
|
||||
(rideId);
|
||||
|
||||
update();
|
||||
} else {
|
||||
MyDialog().getDialog("No Car or Driver Found in your area.".tr,
|
||||
"No Car or Driver Found in your area.".tr, () {
|
||||
Get.back();
|
||||
Get.offAll(const MapPagePassenger());
|
||||
});
|
||||
}
|
||||
|
||||
(rideId);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
int tick = 0; // Move tick outside the function to maintain its state
|
||||
@@ -1679,33 +1691,28 @@ class MapPassengerController extends GetxController {
|
||||
}
|
||||
|
||||
String getLocationArea(double latitude, double longitude) {
|
||||
// Giza Boundary Check
|
||||
if (latitude >= 29.904975 &&
|
||||
latitude <= 30.143372 &&
|
||||
longitude >= 30.787030 &&
|
||||
longitude <= 31.238843) {
|
||||
box.write(BoxName.serverChosen, AppLink.seferGizaServer);
|
||||
return 'Giza';
|
||||
}
|
||||
// Cairo Boundary Check
|
||||
else if (latitude >= 29.918901 &&
|
||||
if (latitude >= 29.918901 &&
|
||||
latitude <= 30.198857 &&
|
||||
longitude >= 31.215009 &&
|
||||
longitude <= 31.532186) {
|
||||
box.write(BoxName.serverChosen, AppLink.seferCairoServer);
|
||||
return 'Cairo';
|
||||
}
|
||||
// Alexandria Boundary Check
|
||||
else if (latitude >= 30.396286 &&
|
||||
} else if (latitude >= 29.904975 &&
|
||||
latitude <= 30.143372 &&
|
||||
longitude >= 30.787030 &&
|
||||
longitude <= 31.238843) {
|
||||
box.write(BoxName.serverChosen, AppLink.seferGizaServer);
|
||||
return 'Giza';
|
||||
} else if (latitude >= 30.396286 &&
|
||||
latitude <= 31.654458 &&
|
||||
longitude >= 29.041139 &&
|
||||
longitude <= 32.626259) {
|
||||
box.write(BoxName.serverChosen, AppLink.seferAlexandriaServer);
|
||||
return 'Alexandria';
|
||||
} else {
|
||||
box.write(BoxName.serverChosen, AppLink.seferCairoServer);
|
||||
return 'Outside';
|
||||
}
|
||||
|
||||
// Return 'Unknown' if outside defined areas
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
Future<bool> getCarsLocationByPassengerAndReloadMarker(
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'package:SEFER/constant/box_name.dart';
|
||||
import 'package:SEFER/main.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../controller/firebase/firbase_messge.dart';
|
||||
import '../../../controller/functions/tts.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
|
||||
@@ -89,8 +92,17 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
|
||||
// borderRadius: BorderRadius.circular(15)),
|
||||
// child: IconButton(
|
||||
// onPressed: () async {
|
||||
// box.remove(BoxName.isVerified);
|
||||
// Get.to(() => SmsSignupEgypt());
|
||||
// FirebaseMessagesController().sendNotificationToAnyWithoutData(
|
||||
// 'Order'.tr,
|
||||
// 'from: ',
|
||||
// // jsonDecode(value)['message'].toString(),
|
||||
// 'dEugS-JOT4Ka5riF4s5TEN:APA91bEDL_W7BuEQGbyL-RMaKiMWDlURXhFuaybe5WurTUV8K5eIooSGe22yY22_U2hEZcfPr46ig1v--l00dbOGiivazxvmTyhUyQQW6lJsuIN-wordGtBxtREyeYtEKvxIa1J4ApEu',
|
||||
// 'order.wav'
|
||||
|
||||
// // polylineCoordinates.toString()
|
||||
// );
|
||||
// // print(box.read(BoxName.tokenFCM));
|
||||
// //
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.voice_chat,
|
||||
@@ -98,32 +110,31 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// AnimatedContainer(
|
||||
// duration: const Duration(microseconds: 200),
|
||||
// width: controller.widthMapTypeAndTraffic,
|
||||
// decoration: BoxDecoration(
|
||||
// color: AppColor.secondaryColor,
|
||||
// border: Border.all(),
|
||||
// borderRadius: BorderRadius.circular(15)),
|
||||
// child: IconButton(
|
||||
// onPressed: () async {
|
||||
// FirebaseMessagesController().sendNotificationToDriverMAP(
|
||||
// '',
|
||||
// 'from: ',
|
||||
// // jsonDecode(value)['message'].toString(),
|
||||
// 'cXavJMQgRACEfYdOnSLDU4:-KwZqsbJvYyIqgkI9oxZCiqyVv9ZnVG7rN0LBf7Nxe9AEcatgHNo0fEomaMWB3ff_SagtNkUuYeHc-GaPETq6Oa',
|
||||
// [],
|
||||
// 'order.wav'
|
||||
|
||||
// // polylineCoordinates.toString()
|
||||
// );
|
||||
// },
|
||||
// icon: const Icon(
|
||||
// Icons.chat,
|
||||
// size: 29,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
AnimatedContainer(
|
||||
duration: const Duration(microseconds: 200),
|
||||
width: controller.widthMapTypeAndTraffic,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.secondaryColor,
|
||||
border: Border.all(),
|
||||
borderRadius: BorderRadius.circular(15)),
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
FirebaseMessagesController().sendNotificationToDriverMAP(
|
||||
'message From passenger'.tr,
|
||||
'My location is correct. You can search for me using the navigation app'
|
||||
.tr,
|
||||
'db9hQ9BfT_2U-ocVHbEAej:APA91bG2YiVN8Dw3bNitehENk0sUPKt7A3zoT6GY_NdbxsMVKX8ouZRI6Ix9ScLSGYz31gugsb2Ag087FXmbPbQkD9E7nwOR7USPrai5euFjZXVHNrz2Byacn8gBTGr8HPV-CGHG81lk',
|
||||
[],
|
||||
'ding.wav',
|
||||
);
|
||||
// print(box.read(BoxName.tokenFCM));
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.chat,
|
||||
size: 29,
|
||||
),
|
||||
),
|
||||
),
|
||||
// AnimatedContainer(
|
||||
// duration: const Duration(microseconds: 200),
|
||||
// width: controller.widthMapTypeAndTraffic,
|
||||
|
||||
Reference in New Issue
Block a user