feat: profile page

This commit is contained in:
efrilm 2025-08-12 21:20:20 +07:00
parent f0dac56802
commit 9458de5059
10 changed files with 669 additions and 2 deletions

View File

@ -1,12 +1,65 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
import '../../components/spacer/spacer.dart';
import 'widgets/account_info.dart';
import 'widgets/app_setting.dart';
import 'widgets/business_setting.dart';
import 'widgets/danger_zone.dart';
import 'widgets/header.dart';
import 'widgets/support.dart';
@RoutePage()
class ProfilePage extends StatelessWidget {
class ProfilePage extends StatefulWidget {
const ProfilePage({super.key});
@override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
@override
Widget build(BuildContext context) {
return Center(child: Text('ProfilePage'));
return Scaffold(
backgroundColor: AppColor.background,
appBar: AppBar(
title: Text(
'Profile',
style: AppStyle.xxl.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w600,
),
),
backgroundColor: AppColor.primary,
elevation: 0,
actions: [
IconButton(
icon: const Icon(Icons.edit, color: AppColor.textWhite),
onPressed: () {
// Navigate to edit profile
},
),
],
),
body: SingleChildScrollView(
child: Column(
children: [
ProfileHeader(),
const SpaceHeight(20),
ProfileAccountInfo(),
const SpaceHeight(12),
ProfileBusinessSetting(),
const SpaceHeight(12),
ProfileAppSetting(),
const SpaceHeight(12),
ProfileSupport(),
const SpaceHeight(12),
ProfileDangerZone(),
const SpaceHeight(30),
],
),
),
);
}
}

View File

@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import 'divider.dart';
import 'profile_tile.dart';
class ProfileAccountInfo extends StatelessWidget {
const ProfileAccountInfo({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: AppValue.margin),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16),
child: Text(
'Account Information',
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
),
ProfileTile(
icon: Icons.email_outlined,
title: 'Email',
subtitle: 'john.doe@business.com',
onTap: () {
// Edit email
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.phone_outlined,
title: 'Phone Number',
subtitle: '+62 812 3456 7890',
onTap: () {
// Edit phone
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.location_on_outlined,
title: 'Address',
subtitle: 'Jl. Merdeka No. 123, Jakarta',
onTap: () {
// Edit address
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.calendar_today_outlined,
title: 'Member Since',
subtitle: 'January 15, 2024',
showArrow: false,
),
],
),
);
}
}

View File

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import 'divider.dart';
import 'profile_switch_tile.dart';
import 'profile_tile.dart';
class ProfileAppSetting extends StatefulWidget {
const ProfileAppSetting({super.key});
@override
State<ProfileAppSetting> createState() => _ProfileAppSettingState();
}
class _ProfileAppSettingState extends State<ProfileAppSetting> {
bool _notificationsEnabled = true;
bool _darkModeEnabled = false;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: AppValue.margin),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16),
child: Text(
'App Settings',
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
),
ProfileSwitchTile(
icon: Icons.notifications_outlined,
title: 'Notifications',
subtitle: 'Receive app notifications',
value: _notificationsEnabled,
onChanged: (value) {
setState(() {
_notificationsEnabled = value;
});
},
),
ProfileDivider(),
ProfileSwitchTile(
icon: Icons.dark_mode_outlined,
title: 'Dark Mode',
subtitle: 'Switch to dark theme',
value: _darkModeEnabled,
onChanged: (value) {
setState(() {
_darkModeEnabled = value;
});
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.language_outlined,
title: 'Language',
subtitle: 'English (US)',
onTap: () {
// Show language selector
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.security_outlined,
title: 'Security & Privacy',
subtitle: 'Manage your security settings',
onTap: () {
// Navigate to security settings
},
),
],
),
);
}
}

View File

@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import 'divider.dart';
import 'profile_tile.dart';
class ProfileBusinessSetting extends StatelessWidget {
const ProfileBusinessSetting({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: AppValue.margin),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16),
child: Text(
'Business Settings',
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
),
ProfileTile(
icon: Icons.business_outlined,
title: 'Business Information',
subtitle: 'Manage your business details',
onTap: () {
// Navigate to business info
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.people_outline,
title: 'Staff Management',
subtitle: 'Manage employees and permissions',
onTap: () {
// Navigate to staff management
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.payment_outlined,
title: 'Payment Methods',
subtitle: 'Configure payment options',
onTap: () {
// Navigate to payment settings
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.receipt_long_outlined,
title: 'Tax Settings',
subtitle: 'Configure tax rates and policies',
onTap: () {
// Navigate to tax settings
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.print_outlined,
title: 'Receipt & Print Settings',
subtitle: 'Configure receipt templates',
onTap: () {
// Navigate to print settings
},
),
],
),
);
}
}

View File

@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import '../../../components/spacer/spacer.dart';
import 'profile_tile.dart';
class ProfileDangerZone extends StatelessWidget {
const ProfileDangerZone({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: AppValue.margin),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.error.withOpacity(0.3)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(Icons.warning_outlined, color: AppColor.error, size: 20),
const SpaceWidth(8),
Text(
'Danger Zone',
style: AppStyle.xl.copyWith(
fontWeight: FontWeight.bold,
color: AppColor.error,
),
),
],
),
),
ProfileTile(
icon: Icons.logout,
title: 'Logout',
subtitle: 'Sign out from your account',
iconColor: AppColor.error,
textColor: AppColor.error,
onTap: () {},
),
],
),
);
}
}

View File

@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class ProfileDivider extends StatelessWidget {
const ProfileDivider({super.key});
@override
Widget build(BuildContext context) {
return Divider(
height: 1,
thickness: 1,
color: AppColor.border,
indent: 16,
endIndent: 16,
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import '../../../components/spacer/spacer.dart';
class ProfileHeader extends StatelessWidget {
const ProfileHeader({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: AppColor.primaryGradient,
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Column(
children: [
const SpaceHeight(20),
// Profile Picture
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: AppColor.textWhite, width: 3),
color: AppColor.primaryLight,
),
child: ClipOval(
child: Container(
color: AppColor.primaryLight,
child: const Icon(
Icons.person,
size: 50,
color: AppColor.textWhite,
),
),
),
),
const SpaceHeight(16),
// Name
Text(
'John Doe',
style: AppStyle.h5.copyWith(
fontSize: 24,
fontWeight: FontWeight.bold,
color: AppColor.textWhite,
),
),
const SpaceHeight(4),
// Role Badge
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
decoration: BoxDecoration(
color: AppColor.textWhite.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'Business Owner',
style: AppStyle.md.copyWith(
color: AppColor.textWhite,
fontWeight: FontWeight.w500,
),
),
),
const SpaceHeight(30),
],
),
);
}
}

View File

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class ProfileSwitchTile extends StatelessWidget {
final IconData icon;
final String title;
final String? subtitle;
final bool value;
final ValueChanged<bool> onChanged;
const ProfileSwitchTile({
super.key,
required this.icon,
required this.title,
this.subtitle,
required this.value,
required this.onChanged,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColor.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: AppColor.primary, size: 20),
),
title: Text(
title,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w500,
color: AppColor.textPrimary,
),
),
subtitle: subtitle != null
? Text(
subtitle!,
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
)
: null,
trailing: Switch(
value: value,
onChanged: onChanged,
activeColor: AppColor.primary,
),
);
}
}

View File

@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
class ProfileTile extends StatelessWidget {
final IconData icon;
final String title;
final String? subtitle;
final VoidCallback? onTap;
final bool showArrow;
final Color? iconColor;
final Color? textColor;
const ProfileTile({
super.key,
required this.icon,
required this.title,
this.subtitle,
this.onTap,
this.showArrow = true,
this.iconColor,
this.textColor,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: (iconColor ?? AppColor.primary).withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: iconColor ?? AppColor.primary, size: 20),
),
title: Text(
title,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w500,
color: textColor ?? AppColor.textPrimary,
),
),
subtitle: subtitle != null
? Text(
subtitle!,
style: AppStyle.md.copyWith(color: AppColor.textSecondary),
)
: null,
trailing: showArrow
? Icon(Icons.chevron_right, color: AppColor.textLight, size: 20)
: null,
onTap: onTap,
);
}
}

View File

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import '../../../../common/theme/theme.dart';
import 'divider.dart';
import 'profile_tile.dart';
class ProfileSupport extends StatelessWidget {
const ProfileSupport({super.key});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: AppValue.margin),
decoration: BoxDecoration(
color: AppColor.surface,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(16),
child: Text(
'Support',
style: AppStyle.xl.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
),
ProfileTile(
icon: Icons.help_outline,
title: 'Help Center',
subtitle: 'Get help and support',
onTap: () {
// Navigate to help center
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.feedback_outlined,
title: 'Send Feedback',
subtitle: 'Help us improve the app',
onTap: () {
// Open feedback form
},
),
ProfileDivider(),
ProfileTile(
icon: Icons.info_outline,
title: 'About',
subtitle: 'App version and information',
onTap: () {
// Show about dialog
},
),
],
),
);
}
}