Implement forgot password functionality and enhance UI in the authentication flow
This commit is contained in:
parent
915471f4c0
commit
8b01161448
@ -4,7 +4,7 @@ import 'package:marco/controller/my_controller.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/widgets/my_validators.dart';
|
||||
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
class ForgotPasswordController extends MyController {
|
||||
MyFormValidator basicValidator = MyFormValidator();
|
||||
bool showPassword = false;
|
||||
@ -35,6 +35,31 @@ class ForgotPasswordController extends MyController {
|
||||
}
|
||||
}
|
||||
|
||||
/// New: Forgot password function
|
||||
Future<void> onForgotPassword() async {
|
||||
if (basicValidator.validateForm()) {
|
||||
update();
|
||||
final data = basicValidator.getData();
|
||||
final email = data['email']?.toString() ?? '';
|
||||
final result = await AuthService.forgotPassword(email);
|
||||
|
||||
if (result != null) {
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Your password reset link was sent.",
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
} else {
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Your password reset link was sent.",
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void gotoLogIn() {
|
||||
Get.toNamed('/auth/login');
|
||||
}
|
||||
|
@ -112,4 +112,89 @@ class AuthService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Forgot password API
|
||||
static Future<Map<String, String>?> forgotPassword(String email) async {
|
||||
final requestBody = {"email": email};
|
||||
|
||||
logger.i("Sending forgot password request with email: $email");
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse("$_baseUrl/auth/forgot-password"),
|
||||
headers: _headers,
|
||||
body: jsonEncode(requestBody),
|
||||
);
|
||||
|
||||
logger.i(
|
||||
"Forgot password API response (${response.statusCode}): ${response.body}");
|
||||
|
||||
final responseData = jsonDecode(response.body);
|
||||
|
||||
if (response.statusCode == 200 && responseData['success'] == true) {
|
||||
logger.i("Forgot password request successful.");
|
||||
return null;
|
||||
} else {
|
||||
return {
|
||||
"error":
|
||||
responseData['message'] ?? "Failed to send password reset link."
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Exception during forgot password request: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
|
||||
// Request demo API
|
||||
static Future<Map<String, String>?> requestDemo(
|
||||
Map<String, dynamic> demoData) async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse("$_baseUrl/market/inquiry"),
|
||||
headers: _headers,
|
||||
body: jsonEncode(demoData),
|
||||
);
|
||||
|
||||
final responseData = jsonDecode(response.body);
|
||||
|
||||
if (response.statusCode == 200 && responseData['success'] == true) {
|
||||
logger.i("Request Demo submitted successfully.");
|
||||
return null;
|
||||
} else {
|
||||
return {
|
||||
"error": responseData['message'] ?? "Failed to submit demo request."
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Exception during request demo: $e");
|
||||
return {"error": "Network error. Please check your connection."};
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<Map<String, dynamic>>?> getIndustries() async {
|
||||
try {
|
||||
final response = await http.get(
|
||||
Uri.parse("$_baseUrl/market/industries"),
|
||||
headers: _headers,
|
||||
);
|
||||
|
||||
logger.i(
|
||||
"Get Industries API response (${response.statusCode}): ${response.body}");
|
||||
|
||||
final responseData = jsonDecode(response.body);
|
||||
|
||||
if (response.statusCode == 200 && responseData['success'] == true) {
|
||||
// Return the list of industries as List<Map<String, dynamic>>
|
||||
final List<dynamic> industriesData = responseData['data'];
|
||||
return industriesData.cast<Map<String, dynamic>>();
|
||||
} else {
|
||||
logger.w("Failed to fetch industries: ${responseData['message']}");
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
logger.e("Exception during getIndustries: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ import 'package:marco/helpers/widgets/my_spacing.dart';
|
||||
import 'package:marco/helpers/widgets/my_text.dart';
|
||||
import 'package:marco/helpers/widgets/my_text_style.dart';
|
||||
import 'package:marco/view/layouts/auth_layout.dart';
|
||||
import 'package:marco/images.dart';
|
||||
import 'package:marco/helpers/theme/app_theme.dart';
|
||||
|
||||
|
||||
class ForgotPasswordScreen extends StatefulWidget {
|
||||
const ForgotPasswordScreen({super.key});
|
||||
@ -26,57 +29,88 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> with UIMixi
|
||||
init: controller,
|
||||
builder: (controller) {
|
||||
return Form(
|
||||
key: controller.basicValidator.formKey,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
MyText.titleLarge("Forgot Password", fontWeight: 600),
|
||||
MySpacing.height(12),
|
||||
MyText.bodyMedium(
|
||||
"Enter the email address associated with your account and we'll send an email instructions on how to recover your password.",
|
||||
key: controller.basicValidator.formKey,
|
||||
child: SingleChildScrollView(
|
||||
padding: MySpacing.xy(2, 40),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: MySpacing.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.primary.withOpacity(0.02),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: contentTheme.primary.withOpacity(0.5),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(
|
||||
child: Image.asset(
|
||||
Images.logoDark,
|
||||
height: 120,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
MySpacing.height(10),
|
||||
MyText.titleLarge("Forgot Password", fontWeight: 600),
|
||||
MySpacing.height(12),
|
||||
MyText.bodyMedium(
|
||||
"Enter your email and we'll send you instructions to reset your password.",
|
||||
fontWeight: 600,
|
||||
xMuted: true),
|
||||
MySpacing.height(12),
|
||||
TextFormField(
|
||||
xMuted: true,
|
||||
),
|
||||
MySpacing.height(12),
|
||||
TextFormField(
|
||||
validator: controller.basicValidator.getValidation('email'),
|
||||
controller: controller.basicValidator.getController('email'),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
style: MyTextStyle.labelMedium(),
|
||||
decoration: InputDecoration(
|
||||
labelText: "Email Address",
|
||||
labelStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
filled: true,
|
||||
fillColor: contentTheme.secondary.withAlpha(36),
|
||||
prefixIcon: Icon(LucideIcons.mail, size: 16),
|
||||
contentPadding: MySpacing.all(15),
|
||||
isDense: true,
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
style: MyTextStyle.labelMedium(),
|
||||
decoration: InputDecoration(
|
||||
labelText: "Email Address",
|
||||
labelStyle: MyTextStyle.bodySmall(xMuted: true),
|
||||
border: OutlineInputBorder(borderSide: BorderSide.none),
|
||||
filled: true,
|
||||
fillColor: theme.cardColor,
|
||||
prefixIcon: Icon(LucideIcons.mail, size: 16),
|
||||
contentPadding: MySpacing.all(15),
|
||||
isDense: true,
|
||||
isCollapsed: true,
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
),
|
||||
),
|
||||
),
|
||||
MySpacing.height(20),
|
||||
Center(
|
||||
child: MyButton.rounded(
|
||||
onPressed: controller.onLogin,
|
||||
elevation: 0,
|
||||
padding: MySpacing.xy(20, 16),
|
||||
backgroundColor: contentTheme.primary,
|
||||
child: MyText.labelMedium('Forgot Password', color: contentTheme.onPrimary),
|
||||
MySpacing.height(20),
|
||||
Center(
|
||||
child: MyButton.rounded(
|
||||
onPressed: controller.onForgotPassword,
|
||||
elevation: 0,
|
||||
padding: MySpacing.xy(20, 16),
|
||||
backgroundColor: Colors.blueAccent,
|
||||
child: MyText.labelMedium(
|
||||
'Send Reset Link',
|
||||
color: contentTheme.onPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: MyButton.text(
|
||||
onPressed: controller.gotoLogIn,
|
||||
elevation: 0,
|
||||
padding: MySpacing.x(16),
|
||||
splashColor: contentTheme.secondary.withValues(alpha:0.1),
|
||||
child: MyText.labelMedium('Back to log in', color: contentTheme.secondary),
|
||||
Center(
|
||||
child: MyButton.text(
|
||||
onPressed: controller.gotoLogIn,
|
||||
elevation: 0,
|
||||
padding: MySpacing.x(16),
|
||||
splashColor:
|
||||
contentTheme.secondary.withValues(alpha: 0.1),
|
||||
child: MyText.labelMedium(
|
||||
'Back to log in',
|
||||
color: contentTheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -10,6 +10,7 @@ import 'package:marco/helpers/widgets/my_text.dart';
|
||||
import 'package:marco/helpers/widgets/my_text_style.dart';
|
||||
import 'package:marco/view/layouts/auth_layout.dart';
|
||||
import 'package:marco/images.dart';
|
||||
import 'package:marco/view/auth/request_demo_bottom_sheet.dart';
|
||||
|
||||
class LoginScreen extends StatefulWidget {
|
||||
const LoginScreen({super.key});
|
||||
@ -194,7 +195,7 @@ class _LoginScreenState extends State<LoginScreen> with UIMixin {
|
||||
elevation: 2,
|
||||
padding: MySpacing.xy(24, 16),
|
||||
borderRadiusAll: 16,
|
||||
backgroundColor: contentTheme.primary,
|
||||
backgroundColor: Colors.blueAccent,
|
||||
child: MyText.labelMedium(
|
||||
'Login',
|
||||
fontWeight: 600,
|
||||
@ -207,10 +208,13 @@ class _LoginScreenState extends State<LoginScreen> with UIMixin {
|
||||
/// Register Link
|
||||
Center(
|
||||
child: MyButton.text(
|
||||
onPressed: controller.gotoRegister,
|
||||
onPressed: () {
|
||||
OrganizationFormBottomSheet.show(context);
|
||||
},
|
||||
elevation: 0,
|
||||
padding: MySpacing.xy(12, 8),
|
||||
splashColor: contentTheme.secondary.withAlpha(30),
|
||||
splashColor:
|
||||
contentTheme.secondary.withAlpha(30),
|
||||
child: MyText.bodySmall(
|
||||
"Request a Demo",
|
||||
color: contentTheme.secondary,
|
||||
|
325
lib/view/auth/request_demo_bottom_sheet.dart
Normal file
325
lib/view/auth/request_demo_bottom_sheet.dart
Normal file
@ -0,0 +1,325 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:marco/helpers/widgets/my_form_validator.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
|
||||
class OrganizationFormBottomSheet {
|
||||
static void show(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (_) => DraggableScrollableSheet(
|
||||
expand: false,
|
||||
initialChildSize: 0.85,
|
||||
minChildSize: 0.5,
|
||||
maxChildSize: 0.95,
|
||||
builder: (context, scrollController) {
|
||||
return _OrganizationForm(scrollController: scrollController);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _OrganizationForm extends StatefulWidget {
|
||||
final ScrollController scrollController;
|
||||
const _OrganizationForm({required this.scrollController});
|
||||
|
||||
@override
|
||||
State<_OrganizationForm> createState() => _OrganizationFormState();
|
||||
}
|
||||
|
||||
class _OrganizationFormState extends State<_OrganizationForm> {
|
||||
final MyFormValidator validator = MyFormValidator();
|
||||
|
||||
List<Map<String, dynamic>> _industries = [];
|
||||
String? _selectedIndustryId;
|
||||
|
||||
final List<String> _sizes = [
|
||||
'1-10',
|
||||
'11-50',
|
||||
'51-200',
|
||||
'201-1000',
|
||||
'1000+',
|
||||
];
|
||||
|
||||
final Map<String, String> _sizeApiMap = {
|
||||
'1-10': 'less than 10',
|
||||
'11-50': '11 to 50',
|
||||
'51-200': '51 to 200',
|
||||
'201-1000': 'more than 200',
|
||||
'1000+': 'more than 1000',
|
||||
};
|
||||
|
||||
String? _selectedSize;
|
||||
bool _agreed = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_loadIndustries();
|
||||
|
||||
validator.addField<String>('organizationName',
|
||||
required: true, controller: TextEditingController());
|
||||
validator.addField<String>('email',
|
||||
required: true, controller: TextEditingController());
|
||||
validator.addField<String>('contactPerson',
|
||||
required: true, controller: TextEditingController());
|
||||
validator.addField<String>('contactNumber',
|
||||
required: true, controller: TextEditingController());
|
||||
validator.addField<String>('about', controller: TextEditingController());
|
||||
validator.addField<String>('address',
|
||||
required: true, controller: TextEditingController());
|
||||
}
|
||||
|
||||
Future<void> _loadIndustries() async {
|
||||
final industries = await AuthService.getIndustries();
|
||||
if (industries != null) {
|
||||
setState(() {
|
||||
_industries = industries;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: SingleChildScrollView(
|
||||
controller: widget.scrollController,
|
||||
child: Form(
|
||||
key: validator.formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 40,
|
||||
height: 5,
|
||||
margin: const EdgeInsets.only(bottom: 20),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Adventure starts here 🚀',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const Text("Make your app management easy and fun!"),
|
||||
const SizedBox(height: 20),
|
||||
_buildTextField('organizationName', 'Organization Name'),
|
||||
_buildTextField('email', 'Email',
|
||||
keyboardType: TextInputType.emailAddress),
|
||||
_buildTextField('contactPerson', 'Contact Person'),
|
||||
_buildTextField('contactNumber', 'Contact Number',
|
||||
keyboardType: TextInputType.phone),
|
||||
_buildTextField('about', 'About Organization'),
|
||||
_buildTextField('address', 'Current Address'),
|
||||
const SizedBox(height: 10),
|
||||
_buildPopupMenuField(
|
||||
'Organization Size',
|
||||
_sizes,
|
||||
_selectedSize,
|
||||
(val) => setState(() => _selectedSize = val),
|
||||
'Please select organization size',
|
||||
),
|
||||
_buildPopupMenuField(
|
||||
'Industry',
|
||||
_industries.map((e) => e['name'] as String).toList(),
|
||||
_selectedIndustryId != null
|
||||
? _industries.firstWhere(
|
||||
(e) => e['id'] == _selectedIndustryId)['name']
|
||||
: null,
|
||||
(val) {
|
||||
setState(() {
|
||||
final selectedIndustry = _industries.firstWhere(
|
||||
(element) => element['name'] == val,
|
||||
orElse: () => {});
|
||||
_selectedIndustryId = selectedIndustry['id'];
|
||||
});
|
||||
},
|
||||
'Please select industry',
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: _agreed,
|
||||
onChanged: (val) => setState(() => _agreed = val ?? false),
|
||||
fillColor: MaterialStateProperty.all(Colors.white),
|
||||
checkColor: Colors.white,
|
||||
side: MaterialStateBorderSide.resolveWith(
|
||||
(states) =>
|
||||
BorderSide(color: Colors.blueAccent, width: 2),
|
||||
),
|
||||
),
|
||||
const Expanded(
|
||||
child: Text('I agree to privacy policy & terms')),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blueAccent,
|
||||
),
|
||||
onPressed: _submitForm,
|
||||
child: const Text("Submit"),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text("Back to login"),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPopupMenuField(
|
||||
String label,
|
||||
List<String> items,
|
||||
String? selectedValue,
|
||||
ValueChanged<String?> onSelected,
|
||||
String errorText,
|
||||
) {
|
||||
final bool hasError = selectedValue == null;
|
||||
final GlobalKey _key = GlobalKey();
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: FormField<String>(
|
||||
validator: (value) => hasError ? errorText : null,
|
||||
builder: (fieldState) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(label,
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[700])),
|
||||
const SizedBox(height: 6),
|
||||
GestureDetector(
|
||||
key: _key,
|
||||
onTap: () async {
|
||||
final RenderBox renderBox =
|
||||
_key.currentContext!.findRenderObject() as RenderBox;
|
||||
final Offset offset = renderBox.localToGlobal(Offset.zero);
|
||||
final Size size = renderBox.size;
|
||||
|
||||
final selected = await showMenu<String>(
|
||||
context: fieldState.context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
offset.dx,
|
||||
offset.dy + size.height,
|
||||
offset.dx + size.width,
|
||||
offset.dy,
|
||||
),
|
||||
items: items
|
||||
.map((item) => PopupMenuItem<String>(
|
||||
value: item,
|
||||
child: Text(item),
|
||||
))
|
||||
.toList(),
|
||||
);
|
||||
if (selected != null) {
|
||||
onSelected(selected);
|
||||
fieldState.didChange(selected);
|
||||
}
|
||||
},
|
||||
child: InputDecorator(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
errorText: fieldState.errorText,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 12, vertical: 14),
|
||||
),
|
||||
child: Text(
|
||||
selectedValue ?? 'Select $label',
|
||||
style: TextStyle(
|
||||
color: selectedValue == null ? Colors.grey : Colors.black,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTextField(String fieldName, String label,
|
||||
{TextInputType keyboardType = TextInputType.text}) {
|
||||
final controller = validator.getController(fieldName);
|
||||
final validatorFunc = validator.getValidation<String>(fieldName);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
keyboardType: keyboardType,
|
||||
decoration: InputDecoration(
|
||||
labelText: label,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
validator: validatorFunc,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _submitForm() async {
|
||||
bool isValid = validator.validateForm();
|
||||
|
||||
if (_selectedSize == null || _selectedIndustryId == null) {
|
||||
isValid = false;
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
if (!_agreed) {
|
||||
isValid = false;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Please agree to the privacy policy & terms')),
|
||||
);
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
final formData = validator.getData();
|
||||
|
||||
final Map<String, dynamic> requestBody = {
|
||||
'organizatioinName': formData['organizationName'],
|
||||
'email': formData['email'],
|
||||
'about': formData['about'],
|
||||
'contactNumber': formData['contactNumber'],
|
||||
'contactPerson': formData['contactPerson'],
|
||||
'industryId': _selectedIndustryId ?? '',
|
||||
'oragnizationSize': _sizeApiMap[_selectedSize] ?? '',
|
||||
'terms': _agreed,
|
||||
'address': formData['address'],
|
||||
};
|
||||
|
||||
final error = await AuthService.requestDemo(requestBody);
|
||||
|
||||
if (error == null) {
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: "Demo request submitted successfully!.",
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
} else {
|
||||
showAppSnackbar(
|
||||
title: "Success",
|
||||
message: (error['error'] ?? 'Unknown error'),
|
||||
type: SnackbarType.success,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -80,7 +80,7 @@ class _LeftBarState extends State<LeftBar>
|
||||
children: [
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: MySpacing.fromLTRB(0, 24, 0, 0),
|
||||
padding: EdgeInsets.only(top: 50),
|
||||
child: InkWell(
|
||||
onTap: () => Get.toNamed('/home'),
|
||||
child: Image.asset(
|
||||
@ -106,7 +106,6 @@ class _LeftBarState extends State<LeftBar>
|
||||
physics: BouncingScrollPhysics(),
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
children: [
|
||||
Divider(),
|
||||
labelWidget("Dashboard"),
|
||||
NavigationItem(
|
||||
iconData: LucideIcons.layout_dashboard,
|
||||
|
Loading…
x
Reference in New Issue
Block a user