Merge with old in branch 'main'
This commit is contained in:
commit
c0ecff7697
@ -657,6 +657,7 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
Set<String?> seenFrom = {};
|
Set<String?> seenFrom = {};
|
||||||
Set<String?> seenTo = {};
|
Set<String?> seenTo = {};
|
||||||
|
|
||||||
|
if (selectedTripType == "Roundtrip") {
|
||||||
for (int i = 1; i <= rowCount; i++) {
|
for (int i = 1; i <= rowCount; i++) {
|
||||||
final fromValue = selectedFrom[i];
|
final fromValue = selectedFrom[i];
|
||||||
final toValue = selectedTo[i];
|
final toValue = selectedTo[i];
|
||||||
@ -670,7 +671,6 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
// errorMessages.remove("from_place_$i");
|
// errorMessages.remove("from_place_$i");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toValue != null) {
|
if (toValue != null) {
|
||||||
if (seenTo.contains(toValue)) {
|
if (seenTo.contains(toValue)) {
|
||||||
errorMessages["to_place_$i"] = "Duplicate Destination ";
|
errorMessages["to_place_$i"] = "Duplicate Destination ";
|
||||||
@ -681,6 +681,7 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Step 3: Sequential Date Comparison
|
// Step 3: Sequential Date Comparison
|
||||||
DateFormat format = DateFormat("dd-MM-yyyy"); // Assumes "12 Jun" format
|
DateFormat format = DateFormat("dd-MM-yyyy"); // Assumes "12 Jun" format
|
||||||
@ -972,7 +973,6 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<String> filterAndSortCountryList(List<String> items, String filter) {
|
List<String> filterAndSortCountryList(List<String> items, String filter) {
|
||||||
|
|
||||||
final lowerFilter = filter.toLowerCase();
|
final lowerFilter = filter.toLowerCase();
|
||||||
|
|
||||||
int getMatchScore(String item) {
|
int getMatchScore(String item) {
|
||||||
@ -994,8 +994,7 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
return 999;
|
return 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
return items
|
return items.where((item) {
|
||||||
.where((item) {
|
|
||||||
final parts = item.split('\n');
|
final parts = item.split('\n');
|
||||||
final cityAndCode = parts[0];
|
final cityAndCode = parts[0];
|
||||||
final airport = parts.length > 1 ? parts[1].toLowerCase() : '';
|
final airport = parts.length > 1 ? parts[1].toLowerCase() : '';
|
||||||
@ -1007,12 +1006,10 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
return code.contains(lowerFilter) ||
|
return code.contains(lowerFilter) ||
|
||||||
city.contains(lowerFilter) ||
|
city.contains(lowerFilter) ||
|
||||||
airport.contains(lowerFilter);
|
airport.contains(lowerFilter);
|
||||||
})
|
}).toList()
|
||||||
.toList()
|
|
||||||
..sort((a, b) => getMatchScore(a).compareTo(getMatchScore(b)));
|
..sort((a, b) => getMatchScore(a).compareTo(getMatchScore(b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildFirstRow(isDesktop) {
|
List<Widget> _buildFirstRow(isDesktop) {
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
@ -1523,8 +1520,6 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -1572,13 +1567,14 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
selectedFrom[index] != null
|
selectedFrom[index] != null
|
||||||
? countryMap[selectedFrom[index]]
|
? countryMap[selectedFrom[index]]
|
||||||
: null,
|
: null,
|
||||||
asyncItems: (String filter) async {
|
items: countryMap.values.toList(),
|
||||||
final allItems = countryMap.values.toSet().toList();
|
// asyncItems: (String filter) async {
|
||||||
print("Original items: ${allItems.length}");
|
// final allItems = countryMap.values.toSet().toList();
|
||||||
final filtered = filterAndSortCountryList(allItems, filter);
|
// print("Original items: ${allItems.length}");
|
||||||
// print("Filtered items: ${filtered.length} -> $filtered");
|
// final filtered = filterAndSortCountryList(allItems, filter);
|
||||||
return filtered;
|
// // print("Filtered items: ${filtered.length} -> $filtered");
|
||||||
},
|
// return filtered;
|
||||||
|
// },
|
||||||
popupProps: PopupProps.menu(
|
popupProps: PopupProps.menu(
|
||||||
fit: FlexFit.loose,
|
fit: FlexFit.loose,
|
||||||
constraints: BoxConstraints(maxHeight: 220),
|
constraints: BoxConstraints(maxHeight: 220),
|
||||||
@ -2875,6 +2871,4 @@ class FlightScreenState extends State<FlightScreen> {
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -273,11 +273,13 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// Check if card_number has at least 16 digits
|
// Check if card_number has at least 16 digits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isCardChecked) {
|
||||||
final cardNumber = data["card_number"]?.toString() ?? '';
|
final cardNumber = data["card_number"]?.toString() ?? '';
|
||||||
if (cardNumber.length < 16) {
|
if (cardNumber.length < 15) {
|
||||||
// Show error or return false
|
// Show error or return false
|
||||||
print("Card number must be 16 digits");
|
print("Card number must be 15 digits");
|
||||||
errorMessages["card_number"] = "Card number must be 16 digits";
|
errorMessages["card_number"] = "Card number must be atleat 15 digits";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
@ -2328,6 +2330,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
onChanged: (bool? value) {
|
onChanged: (bool? value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
errorMessages.remove("card_number");
|
||||||
|
|
||||||
isChecked = value!;
|
isChecked = value!;
|
||||||
// if (isChecked) {
|
// if (isChecked) {
|
||||||
// textControllers["_cardNumber"]
|
// textControllers["_cardNumber"]
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:dropdown_search/dropdown_search.dart';
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_quill/flutter_quill_internal.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
@ -424,9 +425,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
scrollDirection: Axis.vertical,
|
scrollDirection: Axis.vertical,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Row(
|
child: Row(children: _buildOptions()),
|
||||||
children: _buildOptions(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Expanded(
|
: Expanded(
|
||||||
@ -587,9 +586,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
Spacer(),
|
Spacer(),
|
||||||
buildLastNameField(),
|
buildLastNameField(),
|
||||||
Spacer(), // Space after Last Name
|
Spacer(), // Space after Last Name
|
||||||
buildGenderField(),
|
// buildGenderField(),
|
||||||
SizedBox(width: 15),
|
// SizedBox(width: 15),
|
||||||
buildDobField(),
|
// buildDobField(),
|
||||||
|
buildMobileField(),
|
||||||
|
Spacer(),
|
||||||
|
buildAlternateMobileField(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
@ -599,9 +601,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
SizedBox(height: 8), // Vertical space
|
SizedBox(height: 8), // Vertical space
|
||||||
buildLastNameField(),
|
buildLastNameField(),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
buildGenderField(),
|
// buildGenderField(),
|
||||||
SizedBox(height: 8),
|
// SizedBox(height: 8),
|
||||||
buildDobField(),
|
// buildDobField(),
|
||||||
|
buildMobileField(),
|
||||||
|
SizedBox(height: 8), // Space after Last Name
|
||||||
|
buildAlternateMobileField(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -615,21 +620,21 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
? Row(
|
? Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
buildEmailField(),
|
// buildEmailField(),
|
||||||
Spacer(),
|
// Spacer(),
|
||||||
buildMobileField(),
|
// buildMobileField(),
|
||||||
Spacer(), // Space after Last Name
|
// Spacer(), // Space after Last Name
|
||||||
buildAlternateMobileField(),
|
// buildAlternateMobileField(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
buildMobileField(),
|
// buildMobileField(),
|
||||||
SizedBox(height: 8), // Vertical space
|
// SizedBox(height: 8), // Vertical space
|
||||||
buildAlternateMobileField(),
|
// buildAlternateMobileField(),
|
||||||
SizedBox(height: 8),
|
// SizedBox(height: 8),
|
||||||
buildEmailField(),
|
// buildEmailField(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -662,6 +667,8 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (!widget.apiselectedUser) ...[
|
if (!widget.apiselectedUser) ...[
|
||||||
|
buildEmailField(),
|
||||||
|
Spacer(),
|
||||||
buildPassword(),
|
buildPassword(),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: MediaQuery.of(context).size.width * 0.015,
|
width: MediaQuery.of(context).size.width * 0.015,
|
||||||
@ -670,33 +677,37 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Column(
|
: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
buildEmailField(),
|
||||||
width:
|
SizedBox(width: 10),
|
||||||
isDesktop
|
// Spacer(),
|
||||||
? MediaQuery.of(context).size.width * 0.25
|
// Container(
|
||||||
: MediaQuery.of(context).size.width * 0.8,
|
// width:
|
||||||
child: Row(
|
// isDesktop
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
// ? MediaQuery.of(context).size.width * 0.25
|
||||||
children: [
|
// : MediaQuery.of(context).size.width * 0.8,
|
||||||
TextButton(
|
// child: Row(
|
||||||
onPressed: () => _openPopup(),
|
// mainAxisAlignment: MainAxisAlignment.end,
|
||||||
style: TextButton.styleFrom(
|
// children: [
|
||||||
foregroundColor: Color(0xFF114D8B),
|
// TextButton(
|
||||||
textStyle: GoogleFonts.poppins(
|
// onPressed: () => _openPopup(),
|
||||||
fontSize: 12,
|
// style: TextButton.styleFrom(
|
||||||
fontWeight: FontWeight.w400,
|
// foregroundColor: Color(0xFF114D8B),
|
||||||
),
|
// textStyle: GoogleFonts.poppins(
|
||||||
),
|
// fontSize: 12,
|
||||||
child: Text("Change Password"),
|
// fontWeight: FontWeight.w400,
|
||||||
),
|
// ),
|
||||||
],
|
// ),
|
||||||
),
|
// child: Text("Change Password"),
|
||||||
),
|
// ),
|
||||||
|
// ],
|
||||||
SizedBox(height: 1),
|
// ),
|
||||||
|
// ),
|
||||||
|
buildchangPswd(),
|
||||||
|
// SizedBox(height: 1),
|
||||||
|
Spacer(),
|
||||||
buildRole(),
|
buildRole(),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -704,6 +715,8 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (!widget.apiselectedUser) ...[
|
if (!widget.apiselectedUser) ...[
|
||||||
|
buildEmailField(),
|
||||||
|
SizedBox(height: 8),
|
||||||
buildPassword(),
|
buildPassword(),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
buildRole(),
|
buildRole(),
|
||||||
@ -1038,6 +1051,50 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget buildchangPswd() {
|
||||||
|
void _openPopup() {
|
||||||
|
final emailValue = widget.controllers["email"]?.text ?? "";
|
||||||
|
final updaterUserId = widget.userIdApi ?? "";
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return ChangePasswordDialogData(
|
||||||
|
updaterEmail: emailValue,
|
||||||
|
updaterUserId: updaterUserId,
|
||||||
|
layoutColor: layoutColor,
|
||||||
|
isDesktop: widget.isDesktop,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
width:
|
||||||
|
isDesktop
|
||||||
|
? MediaQuery.of(context).size.width * 0.25
|
||||||
|
: MediaQuery.of(context).size.width * 0.8,
|
||||||
|
child: Column(
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 30),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => _openPopup(),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: Color(0xFF114D8B),
|
||||||
|
textStyle: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text("Change Password"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildEmailField() {
|
Widget buildEmailField() {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -1104,6 +1161,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
|
width: MediaQuery.of(context).size.width * 0.12,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@ -1165,6 +1223,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
|
width: MediaQuery.of(context).size.width * 0.12,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@ -1272,7 +1331,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
// padding: const EdgeInsets.all(3.0),
|
// padding: const EdgeInsets.all(3.0),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 2,vertical: 3),
|
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 3),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -1296,7 +1355,10 @@ class PersonalDetailsState extends State<PersonalDetails> {
|
|||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search Country...",
|
hintText: "Search Country...",
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 3,vertical: 3),
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 3,
|
||||||
|
vertical: 3,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -795,28 +795,6 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
print("All tabs completed!");
|
print("All tabs completed!");
|
||||||
// Submit the full form here
|
// Submit the full form here
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!isValidData(data))
|
|
||||||
// {
|
|
||||||
// print("USERDETAILS : $userDetials");
|
|
||||||
// print("Validation Failed: Required fields are missing.");
|
|
||||||
// setState(() {});
|
|
||||||
// return; // Stop execution if validation fails
|
|
||||||
// } else
|
|
||||||
// {
|
|
||||||
// print("USERDETAILS : $userDetials");
|
|
||||||
//
|
|
||||||
// if (currentIndex < tabKeys.length - 1) {
|
|
||||||
// // Move to next tab
|
|
||||||
// setState(() {
|
|
||||||
// selectedTab = tabKeys[currentIndex + 1];
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// // Already at last tab (travel), maybe submit form or show done message
|
|
||||||
// print("All tabs completed!");
|
|
||||||
// // You can trigger full form submit here
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleSubmit() async {
|
void handleSubmit() async {
|
||||||
@ -1351,7 +1329,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
apiselectedUser != null
|
apiselectedUser != null
|
||||||
? Text( "Profile",
|
? Text(
|
||||||
|
"Profile",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: isDesktop ? 15 : 12,
|
fontSize: isDesktop ? 15 : 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@ -1367,11 +1346,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
|||||||
tooltip: 'Go To Users',
|
tooltip: 'Go To Users',
|
||||||
onTap: (context) {
|
onTap: (context) {
|
||||||
context.go("/listUser");
|
context.go("/listUser");
|
||||||
}
|
},
|
||||||
),
|
|
||||||
BreadcrumbItem(
|
|
||||||
title: 'Create New User',
|
|
||||||
),
|
),
|
||||||
|
BreadcrumbItem(title: 'Create New User'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -282,6 +282,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
value,
|
value,
|
||||||
userId,
|
userId,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.isNotEmpty) {
|
if (response.isNotEmpty) {
|
||||||
_clearError(field);
|
_clearError(field);
|
||||||
errorMessages[field] = response['message'] ?? "$label Already Exists";
|
errorMessages[field] = response['message'] ?? "$label Already Exists";
|
||||||
@ -1261,7 +1262,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget buildNationality() {
|
Widget buildNationality() {
|
||||||
List<String> nationalityOptions = ["Indian", "International","other nationality"];
|
List<String> nationalityOptions = [
|
||||||
|
"Indian",
|
||||||
|
"International",
|
||||||
|
"other nationality",
|
||||||
|
];
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user