827 lines
27 KiB
Dart
827 lines
27 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import '../../../../core/utils/media_url.dart';
|
|
|
|
class GeneralSettings {
|
|
const GeneralSettings({
|
|
this.defaultBranch = '',
|
|
this.branchCodeFormat = 'BR-{000}',
|
|
this.timeZone = 'Asia/Kolkata',
|
|
this.language = 'en',
|
|
this.currency = 'INR',
|
|
this.dateFormat = 'dd/MM/yyyy',
|
|
this.timeFormat = 'HH:mm',
|
|
this.numberFormat = '1,234.56',
|
|
});
|
|
|
|
final String defaultBranch;
|
|
final String branchCodeFormat;
|
|
final String timeZone;
|
|
final String language;
|
|
final String currency;
|
|
final String dateFormat;
|
|
final String timeFormat;
|
|
final String numberFormat;
|
|
|
|
GeneralSettings copyWith({
|
|
String? defaultBranch,
|
|
String? branchCodeFormat,
|
|
String? timeZone,
|
|
String? language,
|
|
String? currency,
|
|
String? dateFormat,
|
|
String? timeFormat,
|
|
String? numberFormat,
|
|
}) {
|
|
return GeneralSettings(
|
|
defaultBranch: defaultBranch ?? this.defaultBranch,
|
|
branchCodeFormat: branchCodeFormat ?? this.branchCodeFormat,
|
|
timeZone: timeZone ?? this.timeZone,
|
|
language: language ?? this.language,
|
|
currency: currency ?? this.currency,
|
|
dateFormat: dateFormat ?? this.dateFormat,
|
|
timeFormat: timeFormat ?? this.timeFormat,
|
|
numberFormat: numberFormat ?? this.numberFormat,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'defaultBranch': defaultBranch,
|
|
'branchCodeFormat': branchCodeFormat,
|
|
'timeZone': timeZone,
|
|
'language': language,
|
|
'currency': currency,
|
|
'dateFormat': dateFormat,
|
|
'timeFormat': timeFormat,
|
|
'numberFormat': numberFormat,
|
|
};
|
|
|
|
factory GeneralSettings.fromJson(Map<String, dynamic> json) => GeneralSettings(
|
|
defaultBranch: json['defaultBranch'] as String? ?? '',
|
|
branchCodeFormat: json['branchCodeFormat'] as String? ?? 'BR-{000}',
|
|
timeZone: json['timeZone'] as String? ?? 'Asia/Kolkata',
|
|
language: json['language'] as String? ?? 'en',
|
|
currency: json['currency'] as String? ?? 'INR',
|
|
dateFormat: json['dateFormat'] as String? ?? 'dd/MM/yyyy',
|
|
timeFormat: json['timeFormat'] as String? ?? 'HH:mm',
|
|
numberFormat: json['numberFormat'] as String? ?? '1,234.56',
|
|
);
|
|
}
|
|
|
|
class CompanyProfileSettings {
|
|
const CompanyProfileSettings({
|
|
this.companyName = '',
|
|
this.companyCode = '',
|
|
this.registrationNumber = '',
|
|
this.gstNumber = '',
|
|
this.address = '',
|
|
this.city = '',
|
|
this.state = '',
|
|
this.pincode = '',
|
|
this.email = '',
|
|
this.phone = '',
|
|
this.website = '',
|
|
this.logoUrl = '',
|
|
this.faviconUrl = '',
|
|
});
|
|
|
|
final String companyName;
|
|
final String companyCode;
|
|
final String registrationNumber;
|
|
final String gstNumber;
|
|
final String address;
|
|
final String city;
|
|
final String state;
|
|
final String pincode;
|
|
final String email;
|
|
final String phone;
|
|
final String website;
|
|
final String logoUrl;
|
|
final String faviconUrl;
|
|
|
|
CompanyProfileSettings copyWith({
|
|
String? companyName,
|
|
String? companyCode,
|
|
String? registrationNumber,
|
|
String? gstNumber,
|
|
String? address,
|
|
String? city,
|
|
String? state,
|
|
String? pincode,
|
|
String? email,
|
|
String? phone,
|
|
String? website,
|
|
String? logoUrl,
|
|
String? faviconUrl,
|
|
}) {
|
|
return CompanyProfileSettings(
|
|
companyName: companyName ?? this.companyName,
|
|
companyCode: companyCode ?? this.companyCode,
|
|
registrationNumber: registrationNumber ?? this.registrationNumber,
|
|
gstNumber: gstNumber ?? this.gstNumber,
|
|
address: address ?? this.address,
|
|
city: city ?? this.city,
|
|
state: state ?? this.state,
|
|
pincode: pincode ?? this.pincode,
|
|
email: email ?? this.email,
|
|
phone: phone ?? this.phone,
|
|
website: website ?? this.website,
|
|
logoUrl: logoUrl ?? this.logoUrl,
|
|
faviconUrl: faviconUrl ?? this.faviconUrl,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'companyName': companyName,
|
|
'companyCode': companyCode,
|
|
'registrationNumber': registrationNumber,
|
|
'gstNumber': gstNumber,
|
|
'address': address,
|
|
'city': city,
|
|
'state': state,
|
|
'pincode': pincode,
|
|
'email': email,
|
|
'phone': phone,
|
|
'website': website,
|
|
'logoUrl': logoUrl,
|
|
'faviconUrl': faviconUrl,
|
|
};
|
|
|
|
/// Payload for `PUT /settings/company` ([CompanySettingsBody]).
|
|
Map<String, dynamic> toApiJson() => {
|
|
'org_name': companyName,
|
|
'gstin': gstNumber,
|
|
'mobile': phone,
|
|
'email': email,
|
|
'website': website,
|
|
'address': address,
|
|
'city': city,
|
|
'state': state,
|
|
'pincode': pincode,
|
|
};
|
|
|
|
factory CompanyProfileSettings.fromJson(Map<String, dynamic> json) =>
|
|
CompanyProfileSettings.fromApiJson(json);
|
|
|
|
factory CompanyProfileSettings.fromApiJson(Map<String, dynamic> json) =>
|
|
CompanyProfileSettings(
|
|
companyName: json['org_name'] as String? ??
|
|
json['companyName'] as String? ??
|
|
'',
|
|
companyCode: json['companyCode'] as String? ?? '',
|
|
registrationNumber: json['registrationNumber'] as String? ?? '',
|
|
gstNumber: json['gstin'] as String? ??
|
|
json['gstNumber'] as String? ??
|
|
'',
|
|
address: json['address'] as String? ?? '',
|
|
city: json['city'] as String? ?? '',
|
|
state: json['state'] as String? ?? '',
|
|
pincode: json['pincode'] as String? ?? '',
|
|
email: json['email'] as String? ?? '',
|
|
phone: json['mobile'] as String? ?? json['phone'] as String? ?? '',
|
|
website: json['website'] as String? ?? '',
|
|
logoUrl: resolveMediaUrl(
|
|
json['logo_url'] as String? ??
|
|
json['logoUrl'] as String? ??
|
|
json['logo'] as String?,
|
|
) ??
|
|
'',
|
|
faviconUrl: resolveMediaUrl(
|
|
json['favicon_url'] as String? ??
|
|
json['faviconUrl'] as String? ??
|
|
json['favicon'] as String?,
|
|
) ??
|
|
'',
|
|
);
|
|
}
|
|
|
|
class UiPreferencesSettings {
|
|
const UiPreferencesSettings({
|
|
this.sidebarExpanded = true,
|
|
this.navigationLayout = 'sidebar',
|
|
this.dashboardLayout = 'default',
|
|
this.tableDensity = 'comfortable',
|
|
this.paginationSize = 20,
|
|
});
|
|
|
|
final bool sidebarExpanded;
|
|
final String navigationLayout;
|
|
final String dashboardLayout;
|
|
final String tableDensity;
|
|
final int paginationSize;
|
|
|
|
UiPreferencesSettings copyWith({
|
|
bool? sidebarExpanded,
|
|
String? navigationLayout,
|
|
String? dashboardLayout,
|
|
String? tableDensity,
|
|
int? paginationSize,
|
|
}) {
|
|
return UiPreferencesSettings(
|
|
sidebarExpanded: sidebarExpanded ?? this.sidebarExpanded,
|
|
navigationLayout: navigationLayout ?? this.navigationLayout,
|
|
dashboardLayout: dashboardLayout ?? this.dashboardLayout,
|
|
tableDensity: tableDensity ?? this.tableDensity,
|
|
paginationSize: paginationSize ?? this.paginationSize,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'sidebarExpanded': sidebarExpanded,
|
|
'navigationLayout': navigationLayout,
|
|
'dashboardLayout': dashboardLayout,
|
|
'tableDensity': tableDensity,
|
|
'paginationSize': paginationSize,
|
|
};
|
|
|
|
factory UiPreferencesSettings.fromJson(Map<String, dynamic> json) =>
|
|
UiPreferencesSettings(
|
|
sidebarExpanded: json['sidebarExpanded'] as bool? ?? true,
|
|
navigationLayout: json['navigationLayout'] as String? ?? 'sidebar',
|
|
dashboardLayout: json['dashboardLayout'] as String? ?? 'default',
|
|
tableDensity: json['tableDensity'] as String? ?? 'comfortable',
|
|
paginationSize: json['paginationSize'] as int? ?? 20,
|
|
);
|
|
}
|
|
|
|
class AssetSettingsConfig {
|
|
const AssetSettingsConfig({
|
|
this.codePrefix = 'AST',
|
|
this.runningNumberLength = 6,
|
|
this.autoGenerateCode = true,
|
|
this.warrantyReminderDays = 30,
|
|
this.expiryAlertDays = 7,
|
|
this.qrEnabled = true,
|
|
this.qrFormat = 'asset_id',
|
|
this.labelSize = '50x25mm',
|
|
this.enabledStatuses = const [
|
|
'available',
|
|
'allocated',
|
|
'maintenance',
|
|
'lost',
|
|
'disposed',
|
|
'retired',
|
|
],
|
|
});
|
|
|
|
final String codePrefix;
|
|
final int runningNumberLength;
|
|
final bool autoGenerateCode;
|
|
final int warrantyReminderDays;
|
|
final int expiryAlertDays;
|
|
final bool qrEnabled;
|
|
final String qrFormat;
|
|
final String labelSize;
|
|
final List<String> enabledStatuses;
|
|
|
|
AssetSettingsConfig copyWith({
|
|
String? codePrefix,
|
|
int? runningNumberLength,
|
|
bool? autoGenerateCode,
|
|
int? warrantyReminderDays,
|
|
int? expiryAlertDays,
|
|
bool? qrEnabled,
|
|
String? qrFormat,
|
|
String? labelSize,
|
|
List<String>? enabledStatuses,
|
|
}) {
|
|
return AssetSettingsConfig(
|
|
codePrefix: codePrefix ?? this.codePrefix,
|
|
runningNumberLength: runningNumberLength ?? this.runningNumberLength,
|
|
autoGenerateCode: autoGenerateCode ?? this.autoGenerateCode,
|
|
warrantyReminderDays: warrantyReminderDays ?? this.warrantyReminderDays,
|
|
expiryAlertDays: expiryAlertDays ?? this.expiryAlertDays,
|
|
qrEnabled: qrEnabled ?? this.qrEnabled,
|
|
qrFormat: qrFormat ?? this.qrFormat,
|
|
labelSize: labelSize ?? this.labelSize,
|
|
enabledStatuses: enabledStatuses ?? this.enabledStatuses,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'codePrefix': codePrefix,
|
|
'runningNumberLength': runningNumberLength,
|
|
'autoGenerateCode': autoGenerateCode,
|
|
'warrantyReminderDays': warrantyReminderDays,
|
|
'expiryAlertDays': expiryAlertDays,
|
|
'qrEnabled': qrEnabled,
|
|
'qrFormat': qrFormat,
|
|
'labelSize': labelSize,
|
|
'enabledStatuses': enabledStatuses,
|
|
};
|
|
|
|
factory AssetSettingsConfig.fromJson(Map<String, dynamic> json) =>
|
|
AssetSettingsConfig(
|
|
codePrefix: json['codePrefix'] as String? ?? 'AST',
|
|
runningNumberLength: json['runningNumberLength'] as int? ?? 6,
|
|
autoGenerateCode: json['autoGenerateCode'] as bool? ?? true,
|
|
warrantyReminderDays: json['warrantyReminderDays'] as int? ?? 30,
|
|
expiryAlertDays: json['expiryAlertDays'] as int? ?? 7,
|
|
qrEnabled: json['qrEnabled'] as bool? ?? true,
|
|
qrFormat: json['qrFormat'] as String? ?? 'asset_id',
|
|
labelSize: json['labelSize'] as String? ?? '50x25mm',
|
|
enabledStatuses: (json['enabledStatuses'] as List<dynamic>?)
|
|
?.map((e) => e.toString())
|
|
.toList() ??
|
|
const [
|
|
'available',
|
|
'allocated',
|
|
'maintenance',
|
|
'lost',
|
|
'disposed',
|
|
'retired',
|
|
],
|
|
);
|
|
}
|
|
|
|
class NotificationSettingsConfig {
|
|
const NotificationSettingsConfig({
|
|
this.emailAssetAllocation = true,
|
|
this.emailAssetReturn = true,
|
|
this.emailMaintenanceRequest = true,
|
|
this.emailWarrantyExpiry = true,
|
|
this.smsEnabled = false,
|
|
this.pushEnabled = true,
|
|
this.inAppEnabled = true,
|
|
});
|
|
|
|
final bool emailAssetAllocation;
|
|
final bool emailAssetReturn;
|
|
final bool emailMaintenanceRequest;
|
|
final bool emailWarrantyExpiry;
|
|
final bool smsEnabled;
|
|
final bool pushEnabled;
|
|
final bool inAppEnabled;
|
|
|
|
NotificationSettingsConfig copyWith({
|
|
bool? emailAssetAllocation,
|
|
bool? emailAssetReturn,
|
|
bool? emailMaintenanceRequest,
|
|
bool? emailWarrantyExpiry,
|
|
bool? smsEnabled,
|
|
bool? pushEnabled,
|
|
bool? inAppEnabled,
|
|
}) {
|
|
return NotificationSettingsConfig(
|
|
emailAssetAllocation: emailAssetAllocation ?? this.emailAssetAllocation,
|
|
emailAssetReturn: emailAssetReturn ?? this.emailAssetReturn,
|
|
emailMaintenanceRequest:
|
|
emailMaintenanceRequest ?? this.emailMaintenanceRequest,
|
|
emailWarrantyExpiry: emailWarrantyExpiry ?? this.emailWarrantyExpiry,
|
|
smsEnabled: smsEnabled ?? this.smsEnabled,
|
|
pushEnabled: pushEnabled ?? this.pushEnabled,
|
|
inAppEnabled: inAppEnabled ?? this.inAppEnabled,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'emailAssetAllocation': emailAssetAllocation,
|
|
'emailAssetReturn': emailAssetReturn,
|
|
'emailMaintenanceRequest': emailMaintenanceRequest,
|
|
'emailWarrantyExpiry': emailWarrantyExpiry,
|
|
'smsEnabled': smsEnabled,
|
|
'pushEnabled': pushEnabled,
|
|
'inAppEnabled': inAppEnabled,
|
|
};
|
|
|
|
factory NotificationSettingsConfig.fromJson(Map<String, dynamic> json) =>
|
|
NotificationSettingsConfig(
|
|
emailAssetAllocation: json['emailAssetAllocation'] as bool? ?? true,
|
|
emailAssetReturn: json['emailAssetReturn'] as bool? ?? true,
|
|
emailMaintenanceRequest:
|
|
json['emailMaintenanceRequest'] as bool? ?? true,
|
|
emailWarrantyExpiry: json['emailWarrantyExpiry'] as bool? ?? true,
|
|
smsEnabled: json['smsEnabled'] as bool? ?? false,
|
|
pushEnabled: json['pushEnabled'] as bool? ?? true,
|
|
inAppEnabled: json['inAppEnabled'] as bool? ?? true,
|
|
);
|
|
}
|
|
|
|
class EmailConfigurationSettings {
|
|
const EmailConfigurationSettings({
|
|
this.smtpHost = '',
|
|
this.smtpPort = 587,
|
|
this.smtpUsername = '',
|
|
this.smtpPassword = '',
|
|
this.senderEmail = '',
|
|
this.senderName = '',
|
|
this.allocationTemplate = 'Your asset {{asset_name}} has been allocated.',
|
|
this.returnTemplate = 'Your asset {{asset_name}} has been returned.',
|
|
this.maintenanceTemplate = 'Maintenance request created for {{asset_name}}.',
|
|
this.warrantyTemplate = 'Warranty for {{asset_name}} expires on {{date}}.',
|
|
});
|
|
|
|
final String smtpHost;
|
|
final int smtpPort;
|
|
final String smtpUsername;
|
|
final String smtpPassword;
|
|
final String senderEmail;
|
|
final String senderName;
|
|
final String allocationTemplate;
|
|
final String returnTemplate;
|
|
final String maintenanceTemplate;
|
|
final String warrantyTemplate;
|
|
|
|
EmailConfigurationSettings copyWith({
|
|
String? smtpHost,
|
|
int? smtpPort,
|
|
String? smtpUsername,
|
|
String? smtpPassword,
|
|
String? senderEmail,
|
|
String? senderName,
|
|
String? allocationTemplate,
|
|
String? returnTemplate,
|
|
String? maintenanceTemplate,
|
|
String? warrantyTemplate,
|
|
}) {
|
|
return EmailConfigurationSettings(
|
|
smtpHost: smtpHost ?? this.smtpHost,
|
|
smtpPort: smtpPort ?? this.smtpPort,
|
|
smtpUsername: smtpUsername ?? this.smtpUsername,
|
|
smtpPassword: smtpPassword ?? this.smtpPassword,
|
|
senderEmail: senderEmail ?? this.senderEmail,
|
|
senderName: senderName ?? this.senderName,
|
|
allocationTemplate: allocationTemplate ?? this.allocationTemplate,
|
|
returnTemplate: returnTemplate ?? this.returnTemplate,
|
|
maintenanceTemplate: maintenanceTemplate ?? this.maintenanceTemplate,
|
|
warrantyTemplate: warrantyTemplate ?? this.warrantyTemplate,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'smtpHost': smtpHost,
|
|
'smtpPort': smtpPort,
|
|
'smtpUsername': smtpUsername,
|
|
'smtpPassword': smtpPassword,
|
|
'senderEmail': senderEmail,
|
|
'senderName': senderName,
|
|
'allocationTemplate': allocationTemplate,
|
|
'returnTemplate': returnTemplate,
|
|
'maintenanceTemplate': maintenanceTemplate,
|
|
'warrantyTemplate': warrantyTemplate,
|
|
};
|
|
|
|
/// Payload for `PUT /settings/email` ([EmailSettingsBody]).
|
|
/// Omits blank password so an existing SMTP password is not cleared.
|
|
Map<String, dynamic> toApiJson() {
|
|
final payload = <String, dynamic>{
|
|
'smtp_host': smtpHost,
|
|
'smtp_port': smtpPort,
|
|
'smtp_username': smtpUsername,
|
|
'sender_email': senderEmail,
|
|
'sender_name': senderName,
|
|
};
|
|
if (smtpPassword.isNotEmpty) {
|
|
payload['smtp_password'] = smtpPassword;
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
factory EmailConfigurationSettings.fromJson(Map<String, dynamic> json) =>
|
|
EmailConfigurationSettings.fromApiJson(json);
|
|
|
|
factory EmailConfigurationSettings.fromApiJson(Map<String, dynamic> json) =>
|
|
EmailConfigurationSettings(
|
|
smtpHost: json['smtp_host'] as String? ?? json['smtpHost'] as String? ?? '',
|
|
smtpPort: (json['smtp_port'] as num?)?.toInt() ??
|
|
(json['smtpPort'] as num?)?.toInt() ??
|
|
587,
|
|
smtpUsername:
|
|
json['smtp_username'] as String? ?? json['smtpUsername'] as String? ?? '',
|
|
smtpPassword:
|
|
json['smtp_password'] as String? ?? json['smtpPassword'] as String? ?? '',
|
|
senderEmail:
|
|
json['sender_email'] as String? ?? json['senderEmail'] as String? ?? '',
|
|
senderName:
|
|
json['sender_name'] as String? ?? json['senderName'] as String? ?? '',
|
|
allocationTemplate: json['allocationTemplate'] as String? ??
|
|
'Your asset {{asset_name}} has been allocated.',
|
|
returnTemplate: json['returnTemplate'] as String? ??
|
|
'Your asset {{asset_name}} has been returned.',
|
|
maintenanceTemplate: json['maintenanceTemplate'] as String? ??
|
|
'Maintenance request created for {{asset_name}}.',
|
|
warrantyTemplate: json['warrantyTemplate'] as String? ??
|
|
'Warranty for {{asset_name}} expires on {{date}}.',
|
|
);
|
|
}
|
|
|
|
class SecuritySettingsConfig {
|
|
const SecuritySettingsConfig({
|
|
this.minPasswordLength = 8,
|
|
this.passwordExpiryDays = 90,
|
|
this.otpEnabled = true,
|
|
this.mfaEnabled = false,
|
|
this.sessionTimeoutMinutes = 30,
|
|
this.autoLogout = true,
|
|
this.concurrentLoginControl = false,
|
|
this.loginAttemptLimit = 5,
|
|
this.accountLockDurationMinutes = 15,
|
|
this.auditLoggingEnabled = true,
|
|
this.ipWhitelist = '',
|
|
});
|
|
|
|
final int minPasswordLength;
|
|
final int passwordExpiryDays;
|
|
final bool otpEnabled;
|
|
final bool mfaEnabled;
|
|
final int sessionTimeoutMinutes;
|
|
final bool autoLogout;
|
|
final bool concurrentLoginControl;
|
|
final int loginAttemptLimit;
|
|
final int accountLockDurationMinutes;
|
|
final bool auditLoggingEnabled;
|
|
final String ipWhitelist;
|
|
|
|
SecuritySettingsConfig copyWith({
|
|
int? minPasswordLength,
|
|
int? passwordExpiryDays,
|
|
bool? otpEnabled,
|
|
bool? mfaEnabled,
|
|
int? sessionTimeoutMinutes,
|
|
bool? autoLogout,
|
|
bool? concurrentLoginControl,
|
|
int? loginAttemptLimit,
|
|
int? accountLockDurationMinutes,
|
|
bool? auditLoggingEnabled,
|
|
String? ipWhitelist,
|
|
}) {
|
|
return SecuritySettingsConfig(
|
|
minPasswordLength: minPasswordLength ?? this.minPasswordLength,
|
|
passwordExpiryDays: passwordExpiryDays ?? this.passwordExpiryDays,
|
|
otpEnabled: otpEnabled ?? this.otpEnabled,
|
|
mfaEnabled: mfaEnabled ?? this.mfaEnabled,
|
|
sessionTimeoutMinutes: sessionTimeoutMinutes ?? this.sessionTimeoutMinutes,
|
|
autoLogout: autoLogout ?? this.autoLogout,
|
|
concurrentLoginControl:
|
|
concurrentLoginControl ?? this.concurrentLoginControl,
|
|
loginAttemptLimit: loginAttemptLimit ?? this.loginAttemptLimit,
|
|
accountLockDurationMinutes:
|
|
accountLockDurationMinutes ?? this.accountLockDurationMinutes,
|
|
auditLoggingEnabled: auditLoggingEnabled ?? this.auditLoggingEnabled,
|
|
ipWhitelist: ipWhitelist ?? this.ipWhitelist,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'minPasswordLength': minPasswordLength,
|
|
'passwordExpiryDays': passwordExpiryDays,
|
|
'otpEnabled': otpEnabled,
|
|
'mfaEnabled': mfaEnabled,
|
|
'sessionTimeoutMinutes': sessionTimeoutMinutes,
|
|
'autoLogout': autoLogout,
|
|
'concurrentLoginControl': concurrentLoginControl,
|
|
'loginAttemptLimit': loginAttemptLimit,
|
|
'accountLockDurationMinutes': accountLockDurationMinutes,
|
|
'auditLoggingEnabled': auditLoggingEnabled,
|
|
'ipWhitelist': ipWhitelist,
|
|
};
|
|
|
|
factory SecuritySettingsConfig.fromJson(Map<String, dynamic> json) =>
|
|
SecuritySettingsConfig(
|
|
minPasswordLength: json['minPasswordLength'] as int? ?? 8,
|
|
passwordExpiryDays: json['passwordExpiryDays'] as int? ?? 90,
|
|
otpEnabled: json['otpEnabled'] as bool? ?? true,
|
|
mfaEnabled: json['mfaEnabled'] as bool? ?? false,
|
|
sessionTimeoutMinutes: json['sessionTimeoutMinutes'] as int? ?? 30,
|
|
autoLogout: json['autoLogout'] as bool? ?? true,
|
|
concurrentLoginControl: json['concurrentLoginControl'] as bool? ?? false,
|
|
loginAttemptLimit: json['loginAttemptLimit'] as int? ?? 5,
|
|
accountLockDurationMinutes:
|
|
json['accountLockDurationMinutes'] as int? ?? 15,
|
|
auditLoggingEnabled: json['auditLoggingEnabled'] as bool? ?? true,
|
|
ipWhitelist: json['ipWhitelist'] as String? ?? '',
|
|
);
|
|
}
|
|
|
|
class AppSettings {
|
|
const AppSettings({
|
|
this.general = const GeneralSettings(),
|
|
this.companyProfile = const CompanyProfileSettings(),
|
|
this.uiPreferences = const UiPreferencesSettings(),
|
|
this.asset = const AssetSettingsConfig(),
|
|
this.notifications = const NotificationSettingsConfig(),
|
|
this.email = const EmailConfigurationSettings(),
|
|
this.security = const SecuritySettingsConfig(),
|
|
});
|
|
|
|
final GeneralSettings general;
|
|
final CompanyProfileSettings companyProfile;
|
|
final UiPreferencesSettings uiPreferences;
|
|
final AssetSettingsConfig asset;
|
|
final NotificationSettingsConfig notifications;
|
|
final EmailConfigurationSettings email;
|
|
final SecuritySettingsConfig security;
|
|
|
|
AppSettings copyWith({
|
|
GeneralSettings? general,
|
|
CompanyProfileSettings? companyProfile,
|
|
UiPreferencesSettings? uiPreferences,
|
|
AssetSettingsConfig? asset,
|
|
NotificationSettingsConfig? notifications,
|
|
EmailConfigurationSettings? email,
|
|
SecuritySettingsConfig? security,
|
|
}) {
|
|
return AppSettings(
|
|
general: general ?? this.general,
|
|
companyProfile: companyProfile ?? this.companyProfile,
|
|
uiPreferences: uiPreferences ?? this.uiPreferences,
|
|
asset: asset ?? this.asset,
|
|
notifications: notifications ?? this.notifications,
|
|
email: email ?? this.email,
|
|
security: security ?? this.security,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'general': general.toJson(),
|
|
'companyProfile': companyProfile.toJson(),
|
|
'uiPreferences': uiPreferences.toJson(),
|
|
'asset': asset.toJson(),
|
|
'notifications': notifications.toJson(),
|
|
'email': email.toJson(),
|
|
'security': security.toJson(),
|
|
};
|
|
|
|
factory AppSettings.fromJson(Map<String, dynamic> json) => AppSettings(
|
|
general: GeneralSettings.fromJson(
|
|
json['general'] as Map<String, dynamic>? ?? {},
|
|
),
|
|
companyProfile: CompanyProfileSettings.fromJson(
|
|
json['companyProfile'] as Map<String, dynamic>? ?? {},
|
|
),
|
|
uiPreferences: UiPreferencesSettings.fromJson(
|
|
json['uiPreferences'] as Map<String, dynamic>? ?? {},
|
|
),
|
|
asset: AssetSettingsConfig.fromJson(
|
|
json['asset'] as Map<String, dynamic>? ?? {},
|
|
),
|
|
notifications: NotificationSettingsConfig.fromJson(
|
|
json['notifications'] as Map<String, dynamic>? ?? {},
|
|
),
|
|
email: EmailConfigurationSettings.fromJson(
|
|
json['email'] as Map<String, dynamic>? ?? {},
|
|
),
|
|
security: SecuritySettingsConfig.fromJson(
|
|
json['security'] as Map<String, dynamic>? ?? {},
|
|
),
|
|
);
|
|
}
|
|
|
|
class SettingsSection {
|
|
const SettingsSection({
|
|
required this.id,
|
|
required this.title,
|
|
required this.subtitle,
|
|
required this.icon,
|
|
required this.route,
|
|
this.phase = 1,
|
|
this.hidden = false,
|
|
});
|
|
|
|
final String id;
|
|
final String title;
|
|
final String subtitle;
|
|
final IconData icon;
|
|
final String route;
|
|
final int phase;
|
|
/// When true, the card stays defined but is not shown on the Settings hub.
|
|
final bool hidden;
|
|
}
|
|
|
|
const phase1SettingsSections = [
|
|
SettingsSection(
|
|
id: 'general',
|
|
title: 'General',
|
|
subtitle: 'Regional, branch, and default preferences',
|
|
icon: Icons.tune_outlined,
|
|
route: '/settings/general',
|
|
),
|
|
SettingsSection(
|
|
id: 'company-profile',
|
|
title: 'Company Profile',
|
|
subtitle: 'Company information and branding assets',
|
|
icon: Icons.business_outlined,
|
|
route: '/settings/company-profile',
|
|
),
|
|
SettingsSection(
|
|
id: 'appearance',
|
|
title: 'Appearance',
|
|
subtitle: 'Theme, branding, and UI preferences',
|
|
icon: Icons.palette_outlined,
|
|
route: '/settings/appearance',
|
|
),
|
|
SettingsSection(
|
|
id: 'roles',
|
|
title: 'Roles & Permissions',
|
|
subtitle: 'Manage roles, permissions, and menu access',
|
|
icon: Icons.security_outlined,
|
|
route: '/users-roles?tab=permissions',
|
|
),
|
|
SettingsSection(
|
|
id: 'asset',
|
|
title: 'Asset Settings',
|
|
subtitle: 'Asset codes, statuses, warranty, and QR',
|
|
icon: Icons.inventory_2_outlined,
|
|
route: '/settings/asset',
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'notifications',
|
|
title: 'Notifications',
|
|
subtitle: 'Email, SMS, push, and in-app alerts',
|
|
icon: Icons.notifications_outlined,
|
|
route: '/settings/notifications',
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'email',
|
|
title: 'Email Configuration',
|
|
subtitle: 'SMTP server settings',
|
|
icon: Icons.email_outlined,
|
|
route: '/settings/email',
|
|
),
|
|
SettingsSection(
|
|
id: 'security',
|
|
title: 'Security',
|
|
subtitle: 'Authentication, session, and audit policies',
|
|
icon: Icons.lock_outline,
|
|
route: '/settings/security',
|
|
hidden: true,
|
|
),
|
|
];
|
|
|
|
/// Phase 2 cards are kept for later; currently hidden on the Settings hub.
|
|
const phase2SettingsSections = [
|
|
SettingsSection(
|
|
id: 'workflow',
|
|
title: 'Workflow Settings',
|
|
subtitle: 'Approval workflows and approvers',
|
|
icon: Icons.account_tree_outlined,
|
|
route: '/settings/workflow',
|
|
phase: 2,
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'dashboard',
|
|
title: 'Dashboard',
|
|
subtitle: 'KPI visibility and widget layout',
|
|
icon: Icons.dashboard_outlined,
|
|
route: '/settings/dashboard',
|
|
phase: 2,
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'reports',
|
|
title: 'Reports',
|
|
subtitle: 'Export options and scheduled reports',
|
|
icon: Icons.assessment_outlined,
|
|
route: '/settings/reports',
|
|
phase: 2,
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'storage',
|
|
title: 'Storage',
|
|
subtitle: 'File upload limits and storage provider',
|
|
icon: Icons.cloud_upload_outlined,
|
|
route: '/settings/storage',
|
|
phase: 2,
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'audit',
|
|
title: 'Audit Logs',
|
|
subtitle: 'Log retention and tracked events',
|
|
icon: Icons.history_outlined,
|
|
route: '/settings/audit',
|
|
phase: 2,
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'mobile',
|
|
title: 'Mobile Settings',
|
|
subtitle: 'Mobile login and sync preferences',
|
|
icon: Icons.phone_android_outlined,
|
|
route: '/settings/mobile',
|
|
phase: 2,
|
|
hidden: true,
|
|
),
|
|
SettingsSection(
|
|
id: 'integrations',
|
|
title: 'Integrations',
|
|
subtitle: 'SSO, SMS gateway, and cloud storage',
|
|
icon: Icons.extension_outlined,
|
|
route: '/settings/integrations',
|
|
phase: 2,
|
|
hidden: true,
|
|
),
|
|
];
|
|
|
|
/// Visible Phase 1 cards for the Settings hub.
|
|
List<SettingsSection> get visiblePhase1SettingsSections =>
|
|
phase1SettingsSections.where((s) => !s.hidden).toList();
|
|
|
|
/// Visible Phase 2 cards for the Settings hub (empty while all are hidden).
|
|
List<SettingsSection> get visiblePhase2SettingsSections =>
|
|
phase2SettingsSections.where((s) => !s.hidden).toList();
|