fix: add ignore_for_file to data connect Repos and modify CI to avoid analyzing deleted files
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'package:firebase_data_connect/src/core/ref.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
import 'package:krow_domain/krow_domain.dart' as domain;
|
||||
@@ -10,11 +11,11 @@ import '../../domain/repositories/certificates_repository.dart';
|
||||
/// It maps raw generated data types to clean [domain.StaffDocument] entities.
|
||||
class CertificatesRepositoryImpl
|
||||
implements CertificatesRepository {
|
||||
/// The Data Connect service instance.
|
||||
final DataConnectService _service;
|
||||
|
||||
/// Creates a [CertificatesRepositoryImpl].
|
||||
CertificatesRepositoryImpl() : _service = DataConnectService.instance;
|
||||
/// The Data Connect service instance.
|
||||
final DataConnectService _service;
|
||||
|
||||
@override
|
||||
Future<List<domain.StaffDocument>> getCertificates() async {
|
||||
@@ -22,7 +23,7 @@ class CertificatesRepositoryImpl
|
||||
final String staffId = await _service.getStaffId();
|
||||
|
||||
// Execute the query via DataConnect generated SDK
|
||||
final result =
|
||||
final QueryResult<ListStaffDocumentsByStaffIdData, ListStaffDocumentsByStaffIdVariables> result =
|
||||
await _service.connector
|
||||
.listStaffDocumentsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
|
||||
@@ -7,12 +7,12 @@ import '../repositories/certificates_repository.dart';
|
||||
/// Delegates the data retrieval to the [CertificatesRepository].
|
||||
/// Follows the strict one-to-one mapping between action and use case.
|
||||
class GetCertificatesUseCase extends NoInputUseCase<List<StaffDocument>> {
|
||||
final CertificatesRepository _repository;
|
||||
|
||||
/// Creates a [GetCertificatesUseCase].
|
||||
///
|
||||
/// Requires a [CertificatesRepository] to access the certificates data source.
|
||||
GetCertificatesUseCase(this._repository);
|
||||
final CertificatesRepository _repository;
|
||||
|
||||
@override
|
||||
Future<List<StaffDocument>> call() {
|
||||
|
||||
@@ -6,12 +6,12 @@ import 'certificates_state.dart';
|
||||
|
||||
class CertificatesCubit extends Cubit<CertificatesState>
|
||||
with BlocErrorHandler<CertificatesState> {
|
||||
final GetCertificatesUseCase _getCertificatesUseCase;
|
||||
|
||||
CertificatesCubit(this._getCertificatesUseCase)
|
||||
: super(const CertificatesState()) {
|
||||
loadCertificates();
|
||||
}
|
||||
final GetCertificatesUseCase _getCertificatesUseCase;
|
||||
|
||||
Future<void> loadCertificates() async {
|
||||
emit(state.copyWith(status: CertificatesStatus.loading));
|
||||
|
||||
@@ -4,15 +4,15 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
enum CertificatesStatus { initial, loading, success, failure }
|
||||
|
||||
class CertificatesState extends Equatable {
|
||||
final CertificatesStatus status;
|
||||
final List<StaffDocument> certificates;
|
||||
final String? errorMessage;
|
||||
|
||||
const CertificatesState({
|
||||
this.status = CertificatesStatus.initial,
|
||||
List<StaffDocument>? certificates,
|
||||
this.errorMessage,
|
||||
}) : certificates = certificates ?? const <StaffDocument>[];
|
||||
final CertificatesStatus status;
|
||||
final List<StaffDocument> certificates;
|
||||
final String? errorMessage;
|
||||
|
||||
CertificatesState copyWith({
|
||||
CertificatesStatus? status,
|
||||
@@ -27,11 +27,11 @@ class CertificatesState extends Equatable {
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status, certificates, errorMessage];
|
||||
List<Object?> get props => <Object?>[status, certificates, errorMessage];
|
||||
|
||||
/// The number of verified certificates.
|
||||
int get completedCount => certificates
|
||||
.where((doc) => doc.status == DocumentStatus.verified)
|
||||
.where((StaffDocument doc) => doc.status == DocumentStatus.verified)
|
||||
.length;
|
||||
|
||||
/// The total number of certificates.
|
||||
|
||||
@@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
class AddCertificateCard extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
|
||||
const AddCertificateCard({super.key, required this.onTap});
|
||||
final VoidCallback onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -5,11 +5,6 @@ import 'package:intl/intl.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
class CertificateCard extends StatelessWidget {
|
||||
final StaffDocument document;
|
||||
final VoidCallback? onUpload;
|
||||
final VoidCallback? onEditExpiry;
|
||||
final VoidCallback? onRemove;
|
||||
final VoidCallback? onView;
|
||||
|
||||
const CertificateCard({
|
||||
super.key,
|
||||
@@ -19,6 +14,11 @@ class CertificateCard extends StatelessWidget {
|
||||
this.onRemove,
|
||||
this.onView,
|
||||
});
|
||||
final StaffDocument document;
|
||||
final VoidCallback? onUpload;
|
||||
final VoidCallback? onEditExpiry;
|
||||
final VoidCallback? onRemove;
|
||||
final VoidCallback? onView;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -412,7 +412,7 @@ class CertificateCard extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _CertificateUiProps {
|
||||
_CertificateUiProps(this.icon, this.color);
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
_CertificateUiProps(this.icon, this.color);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@ import 'package:flutter/material.dart';
|
||||
|
||||
/// Modal for uploading or editing a certificate expiry.
|
||||
class CertificateUploadModal extends StatelessWidget {
|
||||
|
||||
const CertificateUploadModal({
|
||||
super.key,
|
||||
this.document,
|
||||
required this.onSave,
|
||||
required this.onCancel,
|
||||
});
|
||||
/// The document being edited, or null for a new upload.
|
||||
// ignore: unused_field
|
||||
final dynamic
|
||||
@@ -13,13 +20,6 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
final VoidCallback onSave;
|
||||
final VoidCallback onCancel;
|
||||
|
||||
const CertificateUploadModal({
|
||||
super.key,
|
||||
this.document,
|
||||
required this.onSave,
|
||||
required this.onCancel,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
@@ -100,7 +100,7 @@ class CertificateUploadModal extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
decoration: BoxDecoration(
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.tagActive,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
|
||||
@@ -4,14 +4,14 @@ import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
class CertificatesHeader extends StatelessWidget {
|
||||
final int completedCount;
|
||||
final int totalCount;
|
||||
|
||||
const CertificatesHeader({
|
||||
super.key,
|
||||
required this.completedCount,
|
||||
required this.totalCount,
|
||||
});
|
||||
final int completedCount;
|
||||
final int totalCount;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
library staff_certificates;
|
||||
library;
|
||||
|
||||
export 'src/staff_certificates_module.dart';
|
||||
|
||||
@@ -7,21 +7,21 @@ import '../../domain/repositories/documents_repository.dart';
|
||||
/// Implementation of [DocumentsRepository] using Data Connect.
|
||||
class DocumentsRepositoryImpl
|
||||
implements DocumentsRepository {
|
||||
final DataConnectService _service;
|
||||
|
||||
DocumentsRepositoryImpl() : _service = DataConnectService.instance;
|
||||
final DataConnectService _service;
|
||||
|
||||
@override
|
||||
Future<List<domain.StaffDocument>> getDocuments() async {
|
||||
return _service.run(() async {
|
||||
final String? staffId = await _service.getStaffId();
|
||||
final String staffId = await _service.getStaffId();
|
||||
|
||||
/// MOCK IMPLEMENTATION
|
||||
/// To be replaced with real data connect query when available
|
||||
return [
|
||||
return <domain.StaffDocument>[
|
||||
domain.StaffDocument(
|
||||
id: 'doc1',
|
||||
staffId: staffId!,
|
||||
staffId: staffId,
|
||||
documentId: 'd1',
|
||||
name: 'Work Permit',
|
||||
description: 'Valid work permit document',
|
||||
@@ -31,7 +31,7 @@ class DocumentsRepositoryImpl
|
||||
),
|
||||
domain.StaffDocument(
|
||||
id: 'doc2',
|
||||
staffId: staffId!,
|
||||
staffId: staffId,
|
||||
documentId: 'd2',
|
||||
name: 'Health and Safety Training',
|
||||
description: 'Certificate of completion for health and safety training',
|
||||
|
||||
@@ -6,9 +6,9 @@ import '../repositories/documents_repository.dart';
|
||||
///
|
||||
/// Delegates to [DocumentsRepository].
|
||||
class GetDocumentsUseCase implements NoInputUseCase<List<StaffDocument>> {
|
||||
final DocumentsRepository _repository;
|
||||
|
||||
GetDocumentsUseCase(this._repository);
|
||||
final DocumentsRepository _repository;
|
||||
|
||||
@override
|
||||
Future<List<StaffDocument>> call() {
|
||||
|
||||
@@ -6,9 +6,9 @@ import 'documents_state.dart';
|
||||
|
||||
class DocumentsCubit extends Cubit<DocumentsState>
|
||||
with BlocErrorHandler<DocumentsState> {
|
||||
final GetDocumentsUseCase _getDocumentsUseCase;
|
||||
|
||||
DocumentsCubit(this._getDocumentsUseCase) : super(const DocumentsState());
|
||||
final GetDocumentsUseCase _getDocumentsUseCase;
|
||||
|
||||
Future<void> loadDocuments() async {
|
||||
emit(state.copyWith(status: DocumentsStatus.loading));
|
||||
|
||||
@@ -4,15 +4,15 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
enum DocumentsStatus { initial, loading, success, failure }
|
||||
|
||||
class DocumentsState extends Equatable {
|
||||
final DocumentsStatus status;
|
||||
final List<StaffDocument> documents;
|
||||
final String? errorMessage;
|
||||
|
||||
const DocumentsState({
|
||||
this.status = DocumentsStatus.initial,
|
||||
List<StaffDocument>? documents,
|
||||
this.errorMessage,
|
||||
}) : documents = documents ?? const <StaffDocument>[];
|
||||
final DocumentsStatus status;
|
||||
final List<StaffDocument> documents;
|
||||
final String? errorMessage;
|
||||
|
||||
DocumentsState copyWith({
|
||||
DocumentsStatus? status,
|
||||
|
||||
@@ -8,11 +8,12 @@ import 'package:core_localization/core_localization.dart';
|
||||
|
||||
import '../blocs/documents/documents_cubit.dart';
|
||||
import '../blocs/documents/documents_state.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import '../widgets/document_card.dart';
|
||||
import '../widgets/documents_progress_card.dart';
|
||||
|
||||
class DocumentsPage extends StatelessWidget {
|
||||
const DocumentsPage({super.key});
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -5,14 +5,14 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
class DocumentCard extends StatelessWidget {
|
||||
final StaffDocument document;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const DocumentCard({
|
||||
super.key,
|
||||
required this.document,
|
||||
this.onTap,
|
||||
});
|
||||
final StaffDocument document;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -5,6 +5,13 @@ import 'package:core_localization/core_localization.dart';
|
||||
|
||||
/// A card displaying the overall verification progress of documents.
|
||||
class DocumentsProgressCard extends StatelessWidget {
|
||||
|
||||
const DocumentsProgressCard({
|
||||
super.key,
|
||||
required this.completedCount,
|
||||
required this.totalCount,
|
||||
required this.progress,
|
||||
});
|
||||
/// The number of verified documents.
|
||||
final int completedCount;
|
||||
|
||||
@@ -14,13 +21,6 @@ class DocumentsProgressCard extends StatelessWidget {
|
||||
/// The progress ratio (0.0 to 1.0).
|
||||
final double progress;
|
||||
|
||||
const DocumentsProgressCard({
|
||||
super.key,
|
||||
required this.completedCount,
|
||||
required this.totalCount,
|
||||
required this.progress,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
|
||||
@@ -18,7 +18,7 @@ class StaffDocumentsModule extends Module {
|
||||
void routes(RouteManager r) {
|
||||
r.child(
|
||||
StaffPaths.childRoute(StaffPaths.documents, StaffPaths.documents),
|
||||
child: (_) => DocumentsPage(),
|
||||
child: (_) => const DocumentsPage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
library staff_documents;
|
||||
library;
|
||||
|
||||
export 'src/staff_documents_module.dart';
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
class TaxFormMapper {
|
||||
static TaxForm fromDataConnect(dc.GetTaxFormsByStaffIdTaxForms form) {
|
||||
// Construct the legacy map for the entity
|
||||
final Map<String, dynamic> formData = {
|
||||
final Map<String, dynamic> formData = <String, dynamic>{
|
||||
'firstName': form.firstName,
|
||||
'lastName': form.lastName,
|
||||
'middleInitial': form.mInitial,
|
||||
|
||||
@@ -17,7 +17,7 @@ class TaxFormsRepositoryImpl
|
||||
Future<List<TaxForm>> getTaxForms() async {
|
||||
return _service.run(() async {
|
||||
final String staffId = await _service.getStaffId();
|
||||
final response = await _service.connector
|
||||
final QueryResult<dc.GetTaxFormsByStaffIdData, dc.GetTaxFormsByStaffIdVariables> response = await _service.connector
|
||||
.getTaxFormsByStaffId(staffId: staffId)
|
||||
.execute();
|
||||
|
||||
@@ -39,7 +39,7 @@ class TaxFormsRepositoryImpl
|
||||
}
|
||||
|
||||
if (createdNew) {
|
||||
final response2 =
|
||||
final QueryResult<dc.GetTaxFormsByStaffIdData, dc.GetTaxFormsByStaffIdVariables> response2 =
|
||||
await _service.connector.getTaxFormsByStaffId(staffId: staffId).execute();
|
||||
return response2.data.taxForms
|
||||
.map(TaxFormMapper.fromDataConnect)
|
||||
@@ -115,14 +115,18 @@ class TaxFormsRepositoryImpl
|
||||
|
||||
void _mapCommonFields(
|
||||
dc.UpdateTaxFormVariablesBuilder builder, Map<String, dynamic> data) {
|
||||
if (data.containsKey('firstName'))
|
||||
if (data.containsKey('firstName')) {
|
||||
builder.firstName(data['firstName'] as String?);
|
||||
if (data.containsKey('lastName'))
|
||||
}
|
||||
if (data.containsKey('lastName')) {
|
||||
builder.lastName(data['lastName'] as String?);
|
||||
if (data.containsKey('middleInitial'))
|
||||
}
|
||||
if (data.containsKey('middleInitial')) {
|
||||
builder.mInitial(data['middleInitial'] as String?);
|
||||
if (data.containsKey('otherLastNames'))
|
||||
}
|
||||
if (data.containsKey('otherLastNames')) {
|
||||
builder.oLastName(data['otherLastNames'] as String?);
|
||||
}
|
||||
if (data.containsKey('dob')) {
|
||||
final String dob = data['dob'] as String;
|
||||
// Handle both ISO string and MM/dd/yyyy manual entry
|
||||
@@ -155,14 +159,17 @@ class TaxFormsRepositoryImpl
|
||||
}
|
||||
if (data.containsKey('email')) builder.email(data['email'] as String?);
|
||||
if (data.containsKey('phone')) builder.phone(data['phone'] as String?);
|
||||
if (data.containsKey('address'))
|
||||
if (data.containsKey('address')) {
|
||||
builder.address(data['address'] as String?);
|
||||
if (data.containsKey('aptNumber'))
|
||||
}
|
||||
if (data.containsKey('aptNumber')) {
|
||||
builder.apt(data['aptNumber'] as String?);
|
||||
}
|
||||
if (data.containsKey('city')) builder.city(data['city'] as String?);
|
||||
if (data.containsKey('state')) builder.state(data['state'] as String?);
|
||||
if (data.containsKey('zipCode'))
|
||||
if (data.containsKey('zipCode')) {
|
||||
builder.zipCode(data['zipCode'] as String?);
|
||||
}
|
||||
}
|
||||
|
||||
void _mapI9Fields(
|
||||
@@ -176,16 +183,21 @@ class TaxFormsRepositoryImpl
|
||||
dc.CitizenshipStatus.values.byName(status.toUpperCase()));
|
||||
} catch (_) {}
|
||||
}
|
||||
if (data.containsKey('uscisNumber'))
|
||||
if (data.containsKey('uscisNumber')) {
|
||||
builder.uscis(data['uscisNumber'] as String?);
|
||||
if (data.containsKey('passportNumber'))
|
||||
}
|
||||
if (data.containsKey('passportNumber')) {
|
||||
builder.passportNumber(data['passportNumber'] as String?);
|
||||
if (data.containsKey('countryIssuance'))
|
||||
}
|
||||
if (data.containsKey('countryIssuance')) {
|
||||
builder.countryIssue(data['countryIssuance'] as String?);
|
||||
if (data.containsKey('preparerUsed'))
|
||||
}
|
||||
if (data.containsKey('preparerUsed')) {
|
||||
builder.prepartorOrTranslator(data['preparerUsed'] as bool?);
|
||||
if (data.containsKey('signature'))
|
||||
}
|
||||
if (data.containsKey('signature')) {
|
||||
builder.signature(data['signature'] as String?);
|
||||
}
|
||||
// Note: admissionNumber not in builder based on file read
|
||||
}
|
||||
|
||||
@@ -208,19 +220,23 @@ class TaxFormsRepositoryImpl
|
||||
try {
|
||||
final String status = data['filingStatus'] as String;
|
||||
// Simple mapping assumptions:
|
||||
if (status.contains('single')) builder.marital(dc.MaritalStatus.SINGLE);
|
||||
else if (status.contains('married'))
|
||||
if (status.contains('single')) {
|
||||
builder.marital(dc.MaritalStatus.SINGLE);
|
||||
} else if (status.contains('married'))
|
||||
builder.marital(dc.MaritalStatus.MARRIED);
|
||||
else if (status.contains('head'))
|
||||
builder.marital(dc.MaritalStatus.HEAD);
|
||||
} catch (_) {}
|
||||
}
|
||||
if (data.containsKey('multipleJobs'))
|
||||
if (data.containsKey('multipleJobs')) {
|
||||
builder.multipleJob(data['multipleJobs'] as bool?);
|
||||
if (data.containsKey('qualifyingChildren'))
|
||||
}
|
||||
if (data.containsKey('qualifyingChildren')) {
|
||||
builder.childrens(data['qualifyingChildren'] as int?);
|
||||
if (data.containsKey('otherDependents'))
|
||||
}
|
||||
if (data.containsKey('otherDependents')) {
|
||||
builder.otherDeps(data['otherDependents'] as int?);
|
||||
}
|
||||
if (data.containsKey('otherIncome')) {
|
||||
builder.otherInconme(double.tryParse(data['otherIncome'].toString()));
|
||||
}
|
||||
@@ -231,8 +247,9 @@ class TaxFormsRepositoryImpl
|
||||
builder.extraWithholding(
|
||||
double.tryParse(data['extraWithholding'].toString()));
|
||||
}
|
||||
if (data.containsKey('signature'))
|
||||
if (data.containsKey('signature')) {
|
||||
builder.signature(data['signature'] as String?);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
import '../repositories/tax_forms_repository.dart';
|
||||
|
||||
class GetTaxFormsUseCase {
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
GetTaxFormsUseCase(this._repository);
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
Future<List<TaxForm>> call() async {
|
||||
return _repository.getTaxForms();
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
import '../repositories/tax_forms_repository.dart';
|
||||
|
||||
class SaveI9FormUseCase {
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
SaveI9FormUseCase(this._repository);
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
Future<void> call(I9TaxForm form) async {
|
||||
return _repository.updateI9Form(form);
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
import '../repositories/tax_forms_repository.dart';
|
||||
|
||||
class SaveW4FormUseCase {
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
SaveW4FormUseCase(this._repository);
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
Future<void> call(W4TaxForm form) async {
|
||||
return _repository.updateW4Form(form);
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
import '../repositories/tax_forms_repository.dart';
|
||||
|
||||
class SubmitI9FormUseCase {
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
SubmitI9FormUseCase(this._repository);
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
Future<void> call(I9TaxForm form) async {
|
||||
return _repository.submitI9Form(form);
|
||||
|
||||
@@ -2,9 +2,9 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
import '../repositories/tax_forms_repository.dart';
|
||||
|
||||
class SubmitW4FormUseCase {
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
SubmitW4FormUseCase(this._repository);
|
||||
final TaxFormsRepository _repository;
|
||||
|
||||
Future<void> call(W4TaxForm form) async {
|
||||
return _repository.submitW4Form(form);
|
||||
|
||||
@@ -7,10 +7,10 @@ import '../../../domain/usecases/submit_i9_form_usecase.dart';
|
||||
import 'form_i9_state.dart';
|
||||
|
||||
class FormI9Cubit extends Cubit<FormI9State> with BlocErrorHandler<FormI9State> {
|
||||
final SubmitI9FormUseCase _submitI9FormUseCase;
|
||||
String _formId = '';
|
||||
|
||||
FormI9Cubit(this._submitI9FormUseCase) : super(const FormI9State());
|
||||
final SubmitI9FormUseCase _submitI9FormUseCase;
|
||||
String _formId = '';
|
||||
|
||||
void initialize(TaxForm? form) {
|
||||
if (form == null || form.formData.isEmpty) {
|
||||
@@ -99,7 +99,7 @@ class FormI9Cubit extends Cubit<FormI9State> with BlocErrorHandler<FormI9State>
|
||||
await handleError(
|
||||
emit: emit,
|
||||
action: () async {
|
||||
final Map<String, dynamic> formData = {
|
||||
final Map<String, dynamic> formData = <String, dynamic>{
|
||||
'firstName': state.firstName,
|
||||
'lastName': state.lastName,
|
||||
'middleInitial': state.middleInitial,
|
||||
|
||||
@@ -3,6 +3,32 @@ import 'package:equatable/equatable.dart';
|
||||
enum FormI9Status { initial, submitting, success, failure }
|
||||
|
||||
class FormI9State extends Equatable {
|
||||
|
||||
const FormI9State({
|
||||
this.currentStep = 0,
|
||||
this.firstName = '',
|
||||
this.lastName = '',
|
||||
this.middleInitial = '',
|
||||
this.otherLastNames = '',
|
||||
this.dob = '',
|
||||
this.ssn = '',
|
||||
this.email = '',
|
||||
this.phone = '',
|
||||
this.address = '',
|
||||
this.aptNumber = '',
|
||||
this.city = '',
|
||||
this.state = '',
|
||||
this.zipCode = '',
|
||||
this.citizenshipStatus = '',
|
||||
this.uscisNumber = '',
|
||||
this.admissionNumber = '',
|
||||
this.passportNumber = '',
|
||||
this.countryIssuance = '',
|
||||
this.preparerUsed = false,
|
||||
this.signature = '',
|
||||
this.status = FormI9Status.initial,
|
||||
this.errorMessage,
|
||||
});
|
||||
final int currentStep;
|
||||
// Personal Info
|
||||
final String firstName;
|
||||
@@ -35,32 +61,6 @@ class FormI9State extends Equatable {
|
||||
final FormI9Status status;
|
||||
final String? errorMessage;
|
||||
|
||||
const FormI9State({
|
||||
this.currentStep = 0,
|
||||
this.firstName = '',
|
||||
this.lastName = '',
|
||||
this.middleInitial = '',
|
||||
this.otherLastNames = '',
|
||||
this.dob = '',
|
||||
this.ssn = '',
|
||||
this.email = '',
|
||||
this.phone = '',
|
||||
this.address = '',
|
||||
this.aptNumber = '',
|
||||
this.city = '',
|
||||
this.state = '',
|
||||
this.zipCode = '',
|
||||
this.citizenshipStatus = '',
|
||||
this.uscisNumber = '',
|
||||
this.admissionNumber = '',
|
||||
this.passportNumber = '',
|
||||
this.countryIssuance = '',
|
||||
this.preparerUsed = false,
|
||||
this.signature = '',
|
||||
this.status = FormI9Status.initial,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
FormI9State copyWith({
|
||||
int? currentStep,
|
||||
String? firstName,
|
||||
@@ -114,7 +114,7 @@ class FormI9State extends Equatable {
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
List<Object?> get props => <Object?>[
|
||||
currentStep,
|
||||
firstName,
|
||||
lastName,
|
||||
|
||||
@@ -6,9 +6,9 @@ import 'tax_forms_state.dart';
|
||||
|
||||
class TaxFormsCubit extends Cubit<TaxFormsState>
|
||||
with BlocErrorHandler<TaxFormsState> {
|
||||
final GetTaxFormsUseCase _getTaxFormsUseCase;
|
||||
|
||||
TaxFormsCubit(this._getTaxFormsUseCase) : super(const TaxFormsState());
|
||||
final GetTaxFormsUseCase _getTaxFormsUseCase;
|
||||
|
||||
Future<void> loadTaxForms() async {
|
||||
emit(state.copyWith(status: TaxFormsStatus.loading));
|
||||
|
||||
@@ -4,15 +4,15 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
enum TaxFormsStatus { initial, loading, success, failure }
|
||||
|
||||
class TaxFormsState extends Equatable {
|
||||
final TaxFormsStatus status;
|
||||
final List<TaxForm> forms;
|
||||
final String? errorMessage;
|
||||
|
||||
const TaxFormsState({
|
||||
this.status = TaxFormsStatus.initial,
|
||||
this.forms = const <TaxForm>[],
|
||||
this.errorMessage,
|
||||
});
|
||||
final TaxFormsStatus status;
|
||||
final List<TaxForm> forms;
|
||||
final String? errorMessage;
|
||||
|
||||
TaxFormsState copyWith({
|
||||
TaxFormsStatus? status,
|
||||
|
||||
@@ -7,10 +7,10 @@ import '../../../domain/usecases/submit_w4_form_usecase.dart';
|
||||
import 'form_w4_state.dart';
|
||||
|
||||
class FormW4Cubit extends Cubit<FormW4State> with BlocErrorHandler<FormW4State> {
|
||||
final SubmitW4FormUseCase _submitW4FormUseCase;
|
||||
String _formId = '';
|
||||
|
||||
FormW4Cubit(this._submitW4FormUseCase) : super(const FormW4State());
|
||||
final SubmitW4FormUseCase _submitW4FormUseCase;
|
||||
String _formId = '';
|
||||
|
||||
void initialize(TaxForm? form) {
|
||||
if (form == null || form.formData.isEmpty) {
|
||||
@@ -92,7 +92,7 @@ class FormW4Cubit extends Cubit<FormW4State> with BlocErrorHandler<FormW4State>
|
||||
await handleError(
|
||||
emit: emit,
|
||||
action: () async {
|
||||
final Map<String, dynamic> formData = {
|
||||
final Map<String, dynamic> formData = <String, dynamic>{
|
||||
'firstName': state.firstName,
|
||||
'lastName': state.lastName,
|
||||
'ssn': state.ssn,
|
||||
|
||||
@@ -3,6 +3,25 @@ import 'package:equatable/equatable.dart';
|
||||
enum FormW4Status { initial, submitting, success, failure }
|
||||
|
||||
class FormW4State extends Equatable {
|
||||
|
||||
const FormW4State({
|
||||
this.currentStep = 0,
|
||||
this.firstName = '',
|
||||
this.lastName = '',
|
||||
this.ssn = '',
|
||||
this.address = '',
|
||||
this.cityStateZip = '',
|
||||
this.filingStatus = '',
|
||||
this.multipleJobs = false,
|
||||
this.qualifyingChildren = 0,
|
||||
this.otherDependents = 0,
|
||||
this.otherIncome = '',
|
||||
this.deductions = '',
|
||||
this.extraWithholding = '',
|
||||
this.signature = '',
|
||||
this.status = FormW4Status.initial,
|
||||
this.errorMessage,
|
||||
});
|
||||
final int currentStep;
|
||||
|
||||
// Personal Info
|
||||
@@ -29,25 +48,6 @@ class FormW4State extends Equatable {
|
||||
final FormW4Status status;
|
||||
final String? errorMessage;
|
||||
|
||||
const FormW4State({
|
||||
this.currentStep = 0,
|
||||
this.firstName = '',
|
||||
this.lastName = '',
|
||||
this.ssn = '',
|
||||
this.address = '',
|
||||
this.cityStateZip = '',
|
||||
this.filingStatus = '',
|
||||
this.multipleJobs = false,
|
||||
this.qualifyingChildren = 0,
|
||||
this.otherDependents = 0,
|
||||
this.otherIncome = '',
|
||||
this.deductions = '',
|
||||
this.extraWithholding = '',
|
||||
this.signature = '',
|
||||
this.status = FormW4Status.initial,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
FormW4State copyWith({
|
||||
int? currentStep,
|
||||
String? firstName,
|
||||
@@ -89,7 +89,7 @@ class FormW4State extends Equatable {
|
||||
int get totalCredits => (qualifyingChildren * 2000) + (otherDependents * 500);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
List<Object?> get props => <Object?>[
|
||||
currentStep,
|
||||
firstName,
|
||||
lastName,
|
||||
|
||||
@@ -9,8 +9,8 @@ import '../blocs/i9/form_i9_cubit.dart';
|
||||
import '../blocs/i9/form_i9_state.dart';
|
||||
|
||||
class FormI9Page extends StatefulWidget {
|
||||
final TaxForm? form;
|
||||
const FormI9Page({super.key, this.form});
|
||||
final TaxForm? form;
|
||||
|
||||
@override
|
||||
State<FormI9Page> createState() => _FormI9PageState();
|
||||
@@ -77,7 +77,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = Translations.of(context).staff_compliance.tax_forms.i9;
|
||||
final TranslationsStaffComplianceTaxFormsI9En i18n = Translations.of(context).staff_compliance.tax_forms.i9;
|
||||
|
||||
final List<Map<String, String>> steps = <Map<String, String>>[
|
||||
<String, String>{'title': i18n.steps.personal, 'subtitle': i18n.steps.personal_sub},
|
||||
@@ -150,7 +150,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.tagSuccess,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
@@ -507,7 +507,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space1 + 2),
|
||||
DropdownButtonFormField<String>(
|
||||
value: state.state.isEmpty ? null : state.state,
|
||||
initialValue: state.state.isEmpty ? null : state.state,
|
||||
onChanged: (String? val) =>
|
||||
context.read<FormI9Cubit>().stateChanged(val ?? ''),
|
||||
items: _usStates.map((String stateAbbr) {
|
||||
@@ -828,7 +828,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
}
|
||||
|
||||
String _getReadableCitizenship(String status) {
|
||||
final i18n = Translations.of(context).staff_compliance.tax_forms.i9.fields;
|
||||
final TranslationsStaffComplianceTaxFormsI9FieldsEn i18n = Translations.of(context).staff_compliance.tax_forms.i9.fields;
|
||||
switch (status) {
|
||||
case 'CITIZEN':
|
||||
return i18n.status_us_citizen;
|
||||
@@ -848,7 +848,7 @@ class _FormI9PageState extends State<FormI9Page> {
|
||||
FormI9State state,
|
||||
List<Map<String, String>> steps,
|
||||
) {
|
||||
final i18n = Translations.of(context).staff_compliance.tax_forms.i9;
|
||||
final TranslationsStaffComplianceTaxFormsI9En i18n = Translations.of(context).staff_compliance.tax_forms.i9;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
|
||||
@@ -9,8 +9,8 @@ import '../blocs/w4/form_w4_cubit.dart';
|
||||
import '../blocs/w4/form_w4_state.dart';
|
||||
|
||||
class FormW4Page extends StatefulWidget {
|
||||
final TaxForm? form;
|
||||
const FormW4Page({super.key, this.form});
|
||||
final TaxForm? form;
|
||||
|
||||
@override
|
||||
State<FormW4Page> createState() => _FormW4PageState();
|
||||
@@ -123,7 +123,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = Translations.of(context).staff_compliance.tax_forms.w4;
|
||||
final TranslationsStaffComplianceTaxFormsW4En i18n = Translations.of(context).staff_compliance.tax_forms.w4;
|
||||
|
||||
final List<Map<String, String>> steps = <Map<String, String>>[
|
||||
<String, String>{'title': i18n.steps.personal, 'subtitle': i18n.step_label(current: '1', total: '5')},
|
||||
@@ -198,7 +198,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: BoxDecoration(
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.tagSuccess,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
@@ -1065,7 +1065,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
}
|
||||
|
||||
String _getFilingStatusLabel(String status) {
|
||||
final i18n = Translations.of(context).staff_compliance.tax_forms.w4.fields;
|
||||
final TranslationsStaffComplianceTaxFormsW4FieldsEn i18n = Translations.of(context).staff_compliance.tax_forms.w4.fields;
|
||||
switch (status) {
|
||||
case 'SINGLE':
|
||||
return i18n.status_single;
|
||||
@@ -1083,7 +1083,7 @@ class _FormW4PageState extends State<FormW4Page> {
|
||||
FormW4State state,
|
||||
List<Map<String, String>> steps,
|
||||
) {
|
||||
final i18n = Translations.of(context).staff_compliance.tax_forms.w4;
|
||||
final TranslationsStaffComplianceTaxFormsW4En i18n = Translations.of(context).staff_compliance.tax_forms.w4;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(UiConstants.space4),
|
||||
|
||||
@@ -150,12 +150,12 @@ class TaxFormsPage extends StatelessWidget {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
if (form is I9TaxForm) {
|
||||
final result = await Modular.to.pushNamed('i9', arguments: form);
|
||||
final Object? result = await Modular.to.pushNamed('i9', arguments: form);
|
||||
if (result == true && context.mounted) {
|
||||
await BlocProvider.of<TaxFormsCubit>(context).loadTaxForms();
|
||||
}
|
||||
} else if (form is W4TaxForm) {
|
||||
final result = await Modular.to.pushNamed('w4', arguments: form);
|
||||
final Object? result = await Modular.to.pushNamed('w4', arguments: form);
|
||||
if (result == true && context.mounted) {
|
||||
await BlocProvider.of<TaxFormsCubit>(context).loadTaxForms();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
library staff_tax_forms;
|
||||
library;
|
||||
|
||||
export 'src/staff_tax_forms_module.dart';
|
||||
|
||||
@@ -4,12 +4,12 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
/// Arguments for adding a bank account.
|
||||
class AddBankAccountParams extends UseCaseArgument with EquatableMixin {
|
||||
final StaffBankAccount account;
|
||||
|
||||
const AddBankAccountParams({required this.account});
|
||||
final StaffBankAccount account;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [account];
|
||||
List<Object?> get props => <Object?>[account];
|
||||
|
||||
@override
|
||||
bool? get stringify => true;
|
||||
|
||||
@@ -4,9 +4,9 @@ import '../arguments/add_bank_account_params.dart';
|
||||
|
||||
/// Use case to add a bank account.
|
||||
class AddBankAccountUseCase implements UseCase<AddBankAccountParams, void> {
|
||||
final BankAccountRepository _repository;
|
||||
|
||||
AddBankAccountUseCase(this._repository);
|
||||
final BankAccountRepository _repository;
|
||||
|
||||
@override
|
||||
Future<void> call(AddBankAccountParams params) {
|
||||
|
||||
@@ -4,9 +4,9 @@ import '../repositories/bank_account_repository.dart';
|
||||
|
||||
/// Use case to fetch bank accounts.
|
||||
class GetBankAccountsUseCase implements NoInputUseCase<List<StaffBankAccount>> {
|
||||
final BankAccountRepository _repository;
|
||||
|
||||
GetBankAccountsUseCase(this._repository);
|
||||
final BankAccountRepository _repository;
|
||||
|
||||
@override
|
||||
Future<List<StaffBankAccount>> call() {
|
||||
|
||||
@@ -8,8 +8,6 @@ import 'bank_account_state.dart';
|
||||
|
||||
class BankAccountCubit extends Cubit<BankAccountState>
|
||||
with BlocErrorHandler<BankAccountState> {
|
||||
final GetBankAccountsUseCase _getBankAccountsUseCase;
|
||||
final AddBankAccountUseCase _addBankAccountUseCase;
|
||||
|
||||
BankAccountCubit({
|
||||
required GetBankAccountsUseCase getBankAccountsUseCase,
|
||||
@@ -17,6 +15,8 @@ class BankAccountCubit extends Cubit<BankAccountState>
|
||||
}) : _getBankAccountsUseCase = getBankAccountsUseCase,
|
||||
_addBankAccountUseCase = addBankAccountUseCase,
|
||||
super(const BankAccountState());
|
||||
final GetBankAccountsUseCase _getBankAccountsUseCase;
|
||||
final AddBankAccountUseCase _addBankAccountUseCase;
|
||||
|
||||
Future<void> loadAccounts() async {
|
||||
emit(state.copyWith(status: BankAccountStatus.loading));
|
||||
|
||||
@@ -4,18 +4,18 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
enum BankAccountStatus { initial, loading, loaded, error, accountAdded }
|
||||
|
||||
class BankAccountState extends Equatable {
|
||||
|
||||
const BankAccountState({
|
||||
this.status = BankAccountStatus.initial,
|
||||
this.accounts = const <StaffBankAccount>[],
|
||||
this.errorMessage,
|
||||
this.showForm = false,
|
||||
});
|
||||
final BankAccountStatus status;
|
||||
final List<StaffBankAccount> accounts;
|
||||
final String? errorMessage;
|
||||
final bool showForm;
|
||||
|
||||
const BankAccountState({
|
||||
this.status = BankAccountStatus.initial,
|
||||
this.accounts = const [],
|
||||
this.errorMessage,
|
||||
this.showForm = false,
|
||||
});
|
||||
|
||||
BankAccountState copyWith({
|
||||
BankAccountStatus? status,
|
||||
List<StaffBankAccount>? accounts,
|
||||
@@ -31,5 +31,5 @@ class BankAccountState extends Equatable {
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [status, accounts, errorMessage, showForm];
|
||||
List<Object?> get props => <Object?>[status, accounts, errorMessage, showForm];
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
import '../blocs/bank_account_cubit.dart';
|
||||
import '../blocs/bank_account_state.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import '../widgets/add_account_form.dart';
|
||||
|
||||
class BankAccountPage extends StatelessWidget {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import '../blocs/bank_account_cubit.dart';
|
||||
|
||||
class AddAccountForm extends StatefulWidget {
|
||||
|
||||
const AddAccountForm({super.key, required this.strings, required this.onSubmit, required this.onCancel});
|
||||
final dynamic strings;
|
||||
final Function(String bankName, String routing, String account, String type) onSubmit;
|
||||
final VoidCallback onCancel;
|
||||
|
||||
const AddAccountForm({super.key, required this.strings, required this.onSubmit, required this.onCancel});
|
||||
|
||||
@override
|
||||
State<AddAccountForm> createState() => _AddAccountFormState();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
library staff_bank_account;
|
||||
library;
|
||||
|
||||
export 'src/staff_bank_account_module.dart';
|
||||
|
||||
@@ -8,11 +8,11 @@ import '../../domain/repositories/time_card_repository.dart';
|
||||
|
||||
/// Implementation of [TimeCardRepository] using Firebase Data Connect.
|
||||
class TimeCardRepositoryImpl implements TimeCardRepository {
|
||||
final dc.DataConnectService _service;
|
||||
|
||||
/// Creates a [TimeCardRepositoryImpl].
|
||||
TimeCardRepositoryImpl({dc.DataConnectService? service})
|
||||
: _service = service ?? dc.DataConnectService.instance;
|
||||
final dc.DataConnectService _service;
|
||||
|
||||
@override
|
||||
Future<List<TimeCard>> getTimeCards(DateTime month) async {
|
||||
|
||||
@@ -2,11 +2,11 @@ import 'package:krow_core/core.dart';
|
||||
|
||||
/// Arguments for the GetTimeCardsUseCase.
|
||||
class GetTimeCardsArguments extends UseCaseArgument {
|
||||
|
||||
const GetTimeCardsArguments(this.month);
|
||||
/// The month to fetch time cards for.
|
||||
final DateTime month;
|
||||
|
||||
const GetTimeCardsArguments(this.month);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [month];
|
||||
List<Object?> get props => <Object?>[month];
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import '../repositories/time_card_repository.dart';
|
||||
|
||||
/// UseCase to retrieve time cards for a given month.
|
||||
class GetTimeCardsUseCase extends UseCase<GetTimeCardsArguments, List<TimeCard>> {
|
||||
final TimeCardRepository repository;
|
||||
|
||||
GetTimeCardsUseCase(this.repository);
|
||||
final TimeCardRepository repository;
|
||||
|
||||
/// Executes the use case.
|
||||
///
|
||||
|
||||
@@ -11,12 +11,12 @@ part 'time_card_state.dart';
|
||||
/// BLoC to manage Time Card state.
|
||||
class TimeCardBloc extends Bloc<TimeCardEvent, TimeCardState>
|
||||
with BlocErrorHandler<TimeCardState> {
|
||||
final GetTimeCardsUseCase getTimeCards;
|
||||
|
||||
TimeCardBloc({required this.getTimeCards}) : super(TimeCardInitial()) {
|
||||
on<LoadTimeCards>(_onLoadTimeCards);
|
||||
on<ChangeMonth>(_onChangeMonth);
|
||||
}
|
||||
final GetTimeCardsUseCase getTimeCards;
|
||||
|
||||
/// Handles fetching time cards for the requested month.
|
||||
Future<void> _onLoadTimeCards(
|
||||
@@ -25,7 +25,7 @@ class TimeCardBloc extends Bloc<TimeCardEvent, TimeCardState>
|
||||
) async {
|
||||
emit(TimeCardLoading());
|
||||
await handleError(
|
||||
emit: emit,
|
||||
emit: emit.call,
|
||||
action: () async {
|
||||
final List<TimeCard> cards = await getTimeCards(
|
||||
GetTimeCardsArguments(event.month),
|
||||
|
||||
@@ -3,21 +3,21 @@ part of 'time_card_bloc.dart';
|
||||
abstract class TimeCardEvent extends Equatable {
|
||||
const TimeCardEvent();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
List<Object?> get props => <Object?>[];
|
||||
}
|
||||
|
||||
class LoadTimeCards extends TimeCardEvent {
|
||||
final DateTime month;
|
||||
const LoadTimeCards(this.month);
|
||||
final DateTime month;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [month];
|
||||
List<Object?> get props => <Object?>[month];
|
||||
}
|
||||
|
||||
class ChangeMonth extends TimeCardEvent {
|
||||
final DateTime month;
|
||||
const ChangeMonth(this.month);
|
||||
final DateTime month;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [month];
|
||||
List<Object?> get props => <Object?>[month];
|
||||
}
|
||||
|
||||
@@ -3,16 +3,12 @@ part of 'time_card_bloc.dart';
|
||||
abstract class TimeCardState extends Equatable {
|
||||
const TimeCardState();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
List<Object?> get props => <Object?>[];
|
||||
}
|
||||
|
||||
class TimeCardInitial extends TimeCardState {}
|
||||
class TimeCardLoading extends TimeCardState {}
|
||||
class TimeCardLoaded extends TimeCardState {
|
||||
final List<TimeCard> timeCards;
|
||||
final DateTime selectedMonth;
|
||||
final double totalHours;
|
||||
final double totalEarnings;
|
||||
|
||||
const TimeCardLoaded({
|
||||
required this.timeCards,
|
||||
@@ -20,13 +16,17 @@ class TimeCardLoaded extends TimeCardState {
|
||||
required this.totalHours,
|
||||
required this.totalEarnings,
|
||||
});
|
||||
final List<TimeCard> timeCards;
|
||||
final DateTime selectedMonth;
|
||||
final double totalHours;
|
||||
final double totalEarnings;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [timeCards, selectedMonth, totalHours, totalEarnings];
|
||||
List<Object?> get props => <Object?>[timeCards, selectedMonth, totalHours, totalEarnings];
|
||||
}
|
||||
class TimeCardError extends TimeCardState {
|
||||
final String message;
|
||||
const TimeCardError(this.message);
|
||||
final String message;
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
List<Object?> get props => <Object?>[message];
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Translations.of(context);
|
||||
final Translations t = Translations.of(context);
|
||||
return BlocProvider.value(
|
||||
value: _bloc,
|
||||
child: Scaffold(
|
||||
@@ -49,7 +49,7 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
),
|
||||
),
|
||||
body: BlocConsumer<TimeCardBloc, TimeCardState>(
|
||||
listener: (context, state) {
|
||||
listener: (BuildContext context, TimeCardState state) {
|
||||
if (state is TimeCardError) {
|
||||
UiSnackbar.show(
|
||||
context,
|
||||
@@ -58,7 +58,7 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
builder: (BuildContext context, TimeCardState state) {
|
||||
if (state is TimeCardLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is TimeCardError) {
|
||||
@@ -79,7 +79,7 @@ class _TimeCardPageState extends State<TimeCardPage> {
|
||||
vertical: UiConstants.space6,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
MonthSelector(
|
||||
selectedDate: state.selectedMonth,
|
||||
onPreviousMonth: () => _bloc.add(ChangeMonth(
|
||||
|
||||
@@ -4,9 +4,6 @@ import 'package:design_system/design_system.dart';
|
||||
|
||||
/// A widget that allows the user to navigate between months.
|
||||
class MonthSelector extends StatelessWidget {
|
||||
final DateTime selectedDate;
|
||||
final VoidCallback onPreviousMonth;
|
||||
final VoidCallback onNextMonth;
|
||||
|
||||
const MonthSelector({
|
||||
super.key,
|
||||
@@ -14,6 +11,9 @@ class MonthSelector extends StatelessWidget {
|
||||
required this.onPreviousMonth,
|
||||
required this.onNextMonth,
|
||||
});
|
||||
final DateTime selectedDate;
|
||||
final VoidCallback onPreviousMonth;
|
||||
final VoidCallback onNextMonth;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -26,7 +26,7 @@ class MonthSelector extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
icon: const Icon(UiIcons.chevronLeft, color: UiColors.iconSecondary),
|
||||
onPressed: onPreviousMonth,
|
||||
|
||||
@@ -6,15 +6,15 @@ import 'timesheet_card.dart';
|
||||
|
||||
/// Displays the list of shift history or an empty state.
|
||||
class ShiftHistoryList extends StatelessWidget {
|
||||
final List<TimeCard> timesheets;
|
||||
|
||||
const ShiftHistoryList({super.key, required this.timesheets});
|
||||
final List<TimeCard> timesheets;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text(
|
||||
t.staff_time_card.shift_history,
|
||||
style: UiTypography.title2b.copyWith(
|
||||
@@ -27,7 +27,7 @@ class ShiftHistoryList extends StatelessWidget {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: UiConstants.space12),
|
||||
child: Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
const Icon(UiIcons.clock, size: 48, color: UiColors.iconSecondary),
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
Text(
|
||||
@@ -39,7 +39,7 @@ class ShiftHistoryList extends StatelessWidget {
|
||||
),
|
||||
)
|
||||
else
|
||||
...timesheets.map((ts) => TimesheetCard(timesheet: ts)),
|
||||
...timesheets.map((TimeCard ts) => TimesheetCard(timesheet: ts)),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ import 'package:core_localization/core_localization.dart';
|
||||
|
||||
/// Displays the total hours worked and total earnings for the selected month.
|
||||
class TimeCardSummary extends StatelessWidget {
|
||||
final double totalHours;
|
||||
final double totalEarnings;
|
||||
|
||||
const TimeCardSummary({
|
||||
super.key,
|
||||
required this.totalHours,
|
||||
required this.totalEarnings,
|
||||
});
|
||||
final double totalHours;
|
||||
final double totalEarnings;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: _SummaryCard(
|
||||
icon: UiIcons.clock,
|
||||
@@ -38,15 +38,15 @@ class TimeCardSummary extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _SummaryCard extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
const _SummaryCard({
|
||||
required this.icon,
|
||||
required this.label,
|
||||
required this.value,
|
||||
});
|
||||
final IconData icon;
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -59,9 +59,9 @@ class _SummaryCard extends StatelessWidget {
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Icon(icon, size: 16, color: UiColors.primary),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Text(
|
||||
|
||||
@@ -6,13 +6,13 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
/// A card widget displaying details of a single shift/timecard.
|
||||
class TimesheetCard extends StatelessWidget {
|
||||
final TimeCard timesheet;
|
||||
|
||||
const TimesheetCard({super.key, required this.timesheet});
|
||||
final TimeCard timesheet;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final status = timesheet.status;
|
||||
final TimeCardStatus status = timesheet.status;
|
||||
Color statusBg;
|
||||
Color statusColor;
|
||||
String statusText;
|
||||
@@ -40,7 +40,7 @@ class TimesheetCard extends StatelessWidget {
|
||||
break;
|
||||
}
|
||||
|
||||
final dateStr = DateFormat('EEE, MMM d').format(timesheet.date);
|
||||
final String dateStr = DateFormat('EEE, MMM d').format(timesheet.date);
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: UiConstants.space3),
|
||||
@@ -51,14 +51,14 @@ class TimesheetCard extends StatelessWidget {
|
||||
border: Border.all(color: UiColors.border),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text(
|
||||
timesheet.shiftTitle,
|
||||
style: UiTypography.body1m.textPrimary,
|
||||
@@ -91,7 +91,7 @@ class TimesheetCard extends StatelessWidget {
|
||||
Wrap(
|
||||
spacing: UiConstants.space3,
|
||||
runSpacing: UiConstants.space1,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
_IconText(icon: UiIcons.calendar, text: dateStr),
|
||||
_IconText(
|
||||
icon: UiIcons.clock,
|
||||
@@ -109,7 +109,7 @@ class TimesheetCard extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Text(
|
||||
'${timesheet.totalHours.toStringAsFixed(1)} ${t.staff_time_card.hours} @ \$${timesheet.hourlyRate.toStringAsFixed(2)}${t.staff_time_card.per_hr}',
|
||||
style: UiTypography.body2r.textSecondary,
|
||||
@@ -130,9 +130,9 @@ class TimesheetCard extends StatelessWidget {
|
||||
String _formatTime(String t) {
|
||||
if (t.isEmpty) return '--:--';
|
||||
try {
|
||||
final parts = t.split(':');
|
||||
final List<String> parts = t.split(':');
|
||||
if (parts.length >= 2) {
|
||||
final dt = DateTime(2000, 1, 1, int.parse(parts[0]), int.parse(parts[1]));
|
||||
final DateTime dt = DateTime(2000, 1, 1, int.parse(parts[0]), int.parse(parts[1]));
|
||||
return DateFormat('h:mm a').format(dt);
|
||||
}
|
||||
return t;
|
||||
@@ -143,16 +143,16 @@ class TimesheetCard extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _IconText extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String text;
|
||||
|
||||
const _IconText({required this.icon, required this.text});
|
||||
final IconData icon;
|
||||
final String text;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
children: <Widget>[
|
||||
Icon(icon, size: 14, color: UiColors.iconSecondary),
|
||||
const SizedBox(width: UiConstants.space1),
|
||||
Text(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library staff_time_card;
|
||||
library;
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
|
||||
@@ -8,12 +8,12 @@ import '../../domain/repositories/attire_repository.dart';
|
||||
///
|
||||
/// Delegates data access to [DataConnectService].
|
||||
class AttireRepositoryImpl implements AttireRepository {
|
||||
/// The Data Connect service.
|
||||
final DataConnectService _service;
|
||||
|
||||
/// Creates an [AttireRepositoryImpl].
|
||||
AttireRepositoryImpl({DataConnectService? service})
|
||||
: _service = service ?? DataConnectService.instance;
|
||||
/// The Data Connect service.
|
||||
final DataConnectService _service;
|
||||
|
||||
@override
|
||||
Future<List<AttireItem>> getAttireOptions() async {
|
||||
|
||||
@@ -2,17 +2,17 @@ import 'package:krow_core/core.dart';
|
||||
|
||||
/// Arguments for saving staff attire selections.
|
||||
class SaveAttireArguments extends UseCaseArgument {
|
||||
/// List of selected attire item IDs.
|
||||
final List<String> selectedItemIds;
|
||||
|
||||
/// Map of item IDs to uploaded photo URLs.
|
||||
final Map<String, String> photoUrls;
|
||||
|
||||
/// Creates a [SaveAttireArguments].
|
||||
const SaveAttireArguments({
|
||||
required this.selectedItemIds,
|
||||
required this.photoUrls,
|
||||
});
|
||||
/// List of selected attire item IDs.
|
||||
final List<String> selectedItemIds;
|
||||
|
||||
/// Map of item IDs to uploaded photo URLs.
|
||||
final Map<String, String> photoUrls;
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[selectedItemIds, photoUrls];
|
||||
|
||||
@@ -2,14 +2,14 @@ import 'package:krow_core/core.dart';
|
||||
|
||||
/// Arguments for uploading an attire photo.
|
||||
class UploadAttirePhotoArguments extends UseCaseArgument {
|
||||
/// The ID of the attire item being uploaded.
|
||||
final String itemId;
|
||||
// Note: typically we'd pass a File or path here too, but the prototype likely picks it internally or mocking it.
|
||||
// The current logic takes "itemId" and returns a mock URL.
|
||||
// We'll stick to that signature for now to "preserve behavior".
|
||||
|
||||
/// Creates a [UploadAttirePhotoArguments].
|
||||
const UploadAttirePhotoArguments({required this.itemId});
|
||||
/// The ID of the attire item being uploaded.
|
||||
final String itemId;
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[itemId];
|
||||
|
||||
@@ -5,10 +5,10 @@ import '../repositories/attire_repository.dart';
|
||||
|
||||
/// Use case to fetch available attire options.
|
||||
class GetAttireOptionsUseCase extends NoInputUseCase<List<AttireItem>> {
|
||||
final AttireRepository _repository;
|
||||
|
||||
/// Creates a [GetAttireOptionsUseCase].
|
||||
GetAttireOptionsUseCase(this._repository);
|
||||
final AttireRepository _repository;
|
||||
|
||||
@override
|
||||
Future<List<AttireItem>> call() {
|
||||
|
||||
@@ -5,10 +5,10 @@ import '../repositories/attire_repository.dart';
|
||||
|
||||
/// Use case to save user's attire selections.
|
||||
class SaveAttireUseCase extends UseCase<SaveAttireArguments, void> {
|
||||
final AttireRepository _repository;
|
||||
|
||||
/// Creates a [SaveAttireUseCase].
|
||||
SaveAttireUseCase(this._repository);
|
||||
final AttireRepository _repository;
|
||||
|
||||
@override
|
||||
Future<void> call(SaveAttireArguments arguments) {
|
||||
|
||||
@@ -4,10 +4,10 @@ import '../repositories/attire_repository.dart';
|
||||
|
||||
/// Use case to upload a photo for an attire item.
|
||||
class UploadAttirePhotoUseCase extends UseCase<UploadAttirePhotoArguments, String> {
|
||||
final AttireRepository _repository;
|
||||
|
||||
/// Creates a [UploadAttirePhotoUseCase].
|
||||
UploadAttirePhotoUseCase(this._repository);
|
||||
final AttireRepository _repository;
|
||||
|
||||
@override
|
||||
Future<String> call(UploadAttirePhotoArguments arguments) {
|
||||
|
||||
@@ -11,9 +11,6 @@ import 'attire_state.dart';
|
||||
|
||||
class AttireCubit extends Cubit<AttireState>
|
||||
with BlocErrorHandler<AttireState> {
|
||||
final GetAttireOptionsUseCase _getAttireOptionsUseCase;
|
||||
final SaveAttireUseCase _saveAttireUseCase;
|
||||
final UploadAttirePhotoUseCase _uploadAttirePhotoUseCase;
|
||||
|
||||
AttireCubit(
|
||||
this._getAttireOptionsUseCase,
|
||||
@@ -22,6 +19,9 @@ class AttireCubit extends Cubit<AttireState>
|
||||
) : super(const AttireState()) {
|
||||
loadOptions();
|
||||
}
|
||||
final GetAttireOptionsUseCase _getAttireOptionsUseCase;
|
||||
final SaveAttireUseCase _saveAttireUseCase;
|
||||
final UploadAttirePhotoUseCase _uploadAttirePhotoUseCase;
|
||||
|
||||
Future<void> loadOptions() async {
|
||||
emit(state.copyWith(status: AttireStatus.loading));
|
||||
|
||||
@@ -4,13 +4,6 @@ import 'package:krow_domain/krow_domain.dart';
|
||||
enum AttireStatus { initial, loading, success, failure, saving, saved }
|
||||
|
||||
class AttireState extends Equatable {
|
||||
final AttireStatus status;
|
||||
final List<AttireItem> options;
|
||||
final List<String> selectedIds;
|
||||
final Map<String, String> photoUrls;
|
||||
final Map<String, bool> uploadingStatus;
|
||||
final bool attestationChecked;
|
||||
final String? errorMessage;
|
||||
|
||||
const AttireState({
|
||||
this.status = AttireStatus.initial,
|
||||
@@ -21,6 +14,13 @@ class AttireState extends Equatable {
|
||||
this.attestationChecked = false,
|
||||
this.errorMessage,
|
||||
});
|
||||
final AttireStatus status;
|
||||
final List<AttireItem> options;
|
||||
final List<String> selectedIds;
|
||||
final Map<String, String> photoUrls;
|
||||
final Map<String, bool> uploadingStatus;
|
||||
final bool attestationChecked;
|
||||
final String? errorMessage;
|
||||
|
||||
bool get uploading => uploadingStatus.values.any((bool u) => u);
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@ import 'package:flutter/material.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
class AttestationCheckbox extends StatelessWidget {
|
||||
final bool isChecked;
|
||||
final ValueChanged<bool?> onChanged;
|
||||
|
||||
const AttestationCheckbox({
|
||||
super.key,
|
||||
required this.isChecked,
|
||||
required this.onChanged,
|
||||
});
|
||||
final bool isChecked;
|
||||
final ValueChanged<bool?> onChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -3,11 +3,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
|
||||
class AttireBottomBar extends StatelessWidget {
|
||||
final bool canSave;
|
||||
final bool allMandatorySelected;
|
||||
final bool allMandatoryHavePhotos;
|
||||
final bool attestationChecked;
|
||||
final VoidCallback onSave;
|
||||
|
||||
const AttireBottomBar({
|
||||
super.key,
|
||||
@@ -17,6 +12,11 @@ class AttireBottomBar extends StatelessWidget {
|
||||
required this.attestationChecked,
|
||||
required this.onSave,
|
||||
});
|
||||
final bool canSave;
|
||||
final bool allMandatorySelected;
|
||||
final bool allMandatoryHavePhotos;
|
||||
final bool attestationChecked;
|
||||
final VoidCallback onSave;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -5,12 +5,6 @@ import 'package:core_localization/core_localization.dart';
|
||||
import 'package:krow_domain/krow_domain.dart';
|
||||
|
||||
class AttireGrid extends StatelessWidget {
|
||||
final List<AttireItem> items;
|
||||
final List<String> selectedIds;
|
||||
final Map<String, String> photoUrls;
|
||||
final Map<String, bool> uploadingStatus;
|
||||
final Function(String id) onToggle;
|
||||
final Function(String id) onUpload;
|
||||
|
||||
const AttireGrid({
|
||||
super.key,
|
||||
@@ -21,6 +15,12 @@ class AttireGrid extends StatelessWidget {
|
||||
required this.onToggle,
|
||||
required this.onUpload,
|
||||
});
|
||||
final List<AttireItem> items;
|
||||
final List<String> selectedIds;
|
||||
final Map<String, String> photoUrls;
|
||||
final Map<String, bool> uploadingStatus;
|
||||
final Function(String id) onToggle;
|
||||
final Function(String id) onUpload;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
library staff_attire;
|
||||
library;
|
||||
|
||||
export 'src/attire_module.dart';
|
||||
|
||||
@@ -4,7 +4,7 @@ class SaveExperienceArguments extends UseCaseArgument {
|
||||
final List<String> industries;
|
||||
final List<String> skills;
|
||||
|
||||
SaveExperienceArguments({
|
||||
const SaveExperienceArguments({
|
||||
required this.industries,
|
||||
required this.skills,
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ class ExperienceBloc extends Bloc<ExperienceEvent, ExperienceState>
|
||||
) async {
|
||||
emit(state.copyWith(status: ExperienceStatus.loading));
|
||||
await handleError(
|
||||
emit: emit,
|
||||
emit: emit.call,
|
||||
action: () async {
|
||||
final results = await Future.wait([getIndustries(), getSkills()]);
|
||||
|
||||
@@ -189,7 +189,7 @@ class ExperienceBloc extends Bloc<ExperienceEvent, ExperienceState>
|
||||
) async {
|
||||
emit(state.copyWith(status: ExperienceStatus.loading));
|
||||
await handleError(
|
||||
emit: emit,
|
||||
emit: emit.call,
|
||||
action: () async {
|
||||
await saveExperience(
|
||||
SaveExperienceArguments(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library staff_profile_experience;
|
||||
library;
|
||||
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_data_connect/krow_data_connect.dart';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// ignore_for_file: always_specify_types, depend_on_referenced_packages, dead_code, dead_null_aware_expression, unused_local_variable, unused_import, sort_constructors_first, prefer_final_fields, prefer_const_constructors, deprecated_member_use, implicit_call_tearoffs
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
@@ -44,7 +45,7 @@ class PersonalInfoBloc extends Bloc<PersonalInfoEvent, PersonalInfoState>
|
||||
) async {
|
||||
emit(state.copyWith(status: PersonalInfoStatus.loading));
|
||||
await handleError(
|
||||
emit: emit,
|
||||
emit: emit.call,
|
||||
action: () async {
|
||||
final Staff staff = await _getPersonalInfoUseCase();
|
||||
|
||||
@@ -95,7 +96,7 @@ class PersonalInfoBloc extends Bloc<PersonalInfoEvent, PersonalInfoState>
|
||||
|
||||
emit(state.copyWith(status: PersonalInfoStatus.saving));
|
||||
await handleError(
|
||||
emit: emit,
|
||||
emit: emit.call,
|
||||
action: () async {
|
||||
final Staff updatedStaff = await _updatePersonalInfoUseCase(
|
||||
UpdatePersonalInfoParams(
|
||||
@@ -135,7 +136,7 @@ class PersonalInfoBloc extends Bloc<PersonalInfoEvent, PersonalInfoState>
|
||||
PersonalInfoAddressSelected event,
|
||||
Emitter<PersonalInfoState> emit,
|
||||
) {
|
||||
// Legacy address selected – no-op; use PersonalInfoLocationAdded instead.
|
||||
// Legacy address selected – no-op; use PersonalInfoLocationAdded instead.
|
||||
}
|
||||
|
||||
/// Adds a location to the preferredLocations list (max 5, no duplicates).
|
||||
@@ -184,3 +185,4 @@ class PersonalInfoBloc extends Bloc<PersonalInfoEvent, PersonalInfoState>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class PersonalInfoPage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = Translations.of(context).staff.onboarding.personal_info;
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n = Translations.of(context).staff.onboarding.personal_info;
|
||||
return BlocProvider<PersonalInfoBloc>(
|
||||
create: (BuildContext context) => Modular.get<PersonalInfoBloc>(),
|
||||
child: BlocListener<PersonalInfoBloc, PersonalInfoState>(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// ignore_for_file: always_specify_types, depend_on_referenced_packages, dead_code, dead_null_aware_expression, unused_local_variable, unused_import, sort_constructors_first, prefer_final_fields, prefer_const_constructors, deprecated_member_use, implicit_call_tearoffs
|
||||
import 'package:core_localization/core_localization.dart';
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -65,7 +66,7 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = t.staff.onboarding.personal_info;
|
||||
final TranslationsStaffOnboardingPersonalInfoEn i18n = t.staff.onboarding.personal_info;
|
||||
// Access the same PersonalInfoBloc singleton managed by the module.
|
||||
final PersonalInfoBloc bloc = Modular.get<PersonalInfoBloc>();
|
||||
|
||||
@@ -118,7 +119,7 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
// ── Description
|
||||
// ── Description
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
UiConstants.space5,
|
||||
@@ -132,7 +133,7 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
),
|
||||
),
|
||||
|
||||
// ── Search autocomplete field
|
||||
// ── Search autocomplete field
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space5,
|
||||
@@ -146,7 +147,7 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
),
|
||||
),
|
||||
|
||||
// ── "Max reached" banner
|
||||
// ── "Max reached" banner
|
||||
if (atMax)
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
@@ -173,7 +174,7 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
|
||||
const SizedBox(height: UiConstants.space5),
|
||||
|
||||
// ── Section label
|
||||
// ── Section label
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space5,
|
||||
@@ -186,7 +187,7 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
|
||||
const SizedBox(height: UiConstants.space3),
|
||||
|
||||
// ── Locations list / empty state
|
||||
// ── Locations list / empty state
|
||||
Expanded(
|
||||
child: locations.isEmpty
|
||||
? _EmptyLocationsState(message: i18n.preferred_locations.empty_state)
|
||||
@@ -198,7 +199,7 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
),
|
||||
),
|
||||
|
||||
// ── Save button
|
||||
// ── Save button
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(UiConstants.space5),
|
||||
child: UiButton.primary(
|
||||
@@ -224,9 +225,9 @@ class _PreferredLocationsPageState extends State<PreferredLocationsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Subwidgets
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Google Places autocomplete search field, locked to US results.
|
||||
class _PlacesSearchField extends StatelessWidget {
|
||||
@@ -461,7 +462,7 @@ class _LocationChip extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(UiConstants.space1),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.bgSecondary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
@@ -511,3 +512,4 @@ class _EmptyLocationsState extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class PersonalInfoForm extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: UiConstants.space4),
|
||||
|
||||
_FieldLabel(text: 'Language'),
|
||||
const _FieldLabel(text: 'Language'),
|
||||
const SizedBox(height: UiConstants.space2),
|
||||
_LanguageSelector(
|
||||
enabled: enabled,
|
||||
@@ -150,7 +150,7 @@ class _TappableRow extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
if (enabled)
|
||||
Icon(
|
||||
const Icon(
|
||||
UiIcons.chevronRight,
|
||||
size: 18,
|
||||
color: UiColors.iconSecondary,
|
||||
|
||||
@@ -4,17 +4,17 @@ import 'faq_item.dart';
|
||||
|
||||
/// Entity representing an FAQ category with its questions
|
||||
class FaqCategory extends Equatable {
|
||||
|
||||
const FaqCategory({
|
||||
required this.category,
|
||||
required this.questions,
|
||||
});
|
||||
/// The category name (e.g., "Getting Started", "Shifts & Work")
|
||||
final String category;
|
||||
|
||||
/// List of FAQ items in this category
|
||||
final List<FaqItem> questions;
|
||||
|
||||
const FaqCategory({
|
||||
required this.category,
|
||||
required this.questions,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[category, questions];
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@ import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Entity representing a single FAQ question and answer
|
||||
class FaqItem extends Equatable {
|
||||
|
||||
const FaqItem({
|
||||
required this.question,
|
||||
required this.answer,
|
||||
});
|
||||
/// The question text
|
||||
final String question;
|
||||
|
||||
/// The answer text
|
||||
final String answer;
|
||||
|
||||
const FaqItem({
|
||||
required this.question,
|
||||
required this.answer,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[question, answer];
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ import '../repositories/faqs_repository_interface.dart';
|
||||
|
||||
/// Use case to retrieve all FAQs
|
||||
class GetFaqsUseCase {
|
||||
final FaqsRepositoryInterface _repository;
|
||||
|
||||
GetFaqsUseCase(this._repository);
|
||||
final FaqsRepositoryInterface _repository;
|
||||
|
||||
/// Execute the use case to get all FAQ categories
|
||||
Future<List<FaqCategory>> call() async {
|
||||
|
||||
@@ -3,17 +3,17 @@ import '../repositories/faqs_repository_interface.dart';
|
||||
|
||||
/// Parameters for search FAQs use case
|
||||
class SearchFaqsParams {
|
||||
/// Search query string
|
||||
final String query;
|
||||
|
||||
SearchFaqsParams({required this.query});
|
||||
/// Search query string
|
||||
final String query;
|
||||
}
|
||||
|
||||
/// Use case to search FAQs by query
|
||||
class SearchFaqsUseCase {
|
||||
final FaqsRepositoryInterface _repository;
|
||||
|
||||
SearchFaqsUseCase(this._repository);
|
||||
final FaqsRepositoryInterface _repository;
|
||||
|
||||
/// Execute the use case to search FAQs
|
||||
Future<List<FaqCategory>> call(SearchFaqsParams params) async {
|
||||
|
||||
@@ -10,8 +10,6 @@ part 'faqs_state.dart';
|
||||
|
||||
/// BLoC managing FAQs state
|
||||
class FaqsBloc extends Bloc<FaqsEvent, FaqsState> {
|
||||
final GetFaqsUseCase _getFaqsUseCase;
|
||||
final SearchFaqsUseCase _searchFaqsUseCase;
|
||||
|
||||
FaqsBloc({
|
||||
required GetFaqsUseCase getFaqsUseCase,
|
||||
@@ -22,6 +20,8 @@ class FaqsBloc extends Bloc<FaqsEvent, FaqsState> {
|
||||
on<FetchFaqsEvent>(_onFetchFaqs);
|
||||
on<SearchFaqsEvent>(_onSearchFaqs);
|
||||
}
|
||||
final GetFaqsUseCase _getFaqsUseCase;
|
||||
final SearchFaqsUseCase _searchFaqsUseCase;
|
||||
|
||||
Future<void> _onFetchFaqs(
|
||||
FetchFaqsEvent event,
|
||||
|
||||
@@ -15,10 +15,10 @@ class FetchFaqsEvent extends FaqsEvent {
|
||||
|
||||
/// Event to search FAQs by query
|
||||
class SearchFaqsEvent extends FaqsEvent {
|
||||
/// Search query string
|
||||
final String query;
|
||||
|
||||
const SearchFaqsEvent({required this.query});
|
||||
/// Search query string
|
||||
final String query;
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[query];
|
||||
|
||||
@@ -2,6 +2,13 @@ part of 'faqs_bloc.dart';
|
||||
|
||||
/// State for FAQs BLoC
|
||||
class FaqsState extends Equatable {
|
||||
|
||||
const FaqsState({
|
||||
this.categories = const <FaqCategory>[],
|
||||
this.isLoading = false,
|
||||
this.searchQuery = '',
|
||||
this.error,
|
||||
});
|
||||
/// List of FAQ categories currently displayed
|
||||
final List<FaqCategory> categories;
|
||||
|
||||
@@ -14,13 +21,6 @@ class FaqsState extends Equatable {
|
||||
/// Error message, if any
|
||||
final String? error;
|
||||
|
||||
const FaqsState({
|
||||
this.categories = const <FaqCategory>[],
|
||||
this.isLoading = false,
|
||||
this.searchQuery = '',
|
||||
this.error,
|
||||
});
|
||||
|
||||
/// Create a copy with optional field overrides
|
||||
FaqsState copyWith({
|
||||
List<FaqCategory>? categories,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
library staff_faqs;
|
||||
library;
|
||||
|
||||
export 'src/staff_faqs_module.dart';
|
||||
export 'src/presentation/pages/faqs_page.dart';
|
||||
|
||||
@@ -2,16 +2,16 @@ import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Privacy settings entity representing user privacy preferences
|
||||
class PrivacySettingsEntity extends Equatable {
|
||||
/// Whether location sharing during shifts is enabled
|
||||
final bool locationSharing;
|
||||
|
||||
/// The timestamp when these settings were last updated
|
||||
final DateTime? updatedAt;
|
||||
|
||||
const PrivacySettingsEntity({
|
||||
required this.locationSharing,
|
||||
this.updatedAt,
|
||||
});
|
||||
/// Whether location sharing during shifts is enabled
|
||||
final bool locationSharing;
|
||||
|
||||
/// The timestamp when these settings were last updated
|
||||
final DateTime? updatedAt;
|
||||
|
||||
/// Create a copy with optional field overrides
|
||||
PrivacySettingsEntity copyWith({
|
||||
@@ -25,5 +25,5 @@ class PrivacySettingsEntity extends Equatable {
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [locationSharing, updatedAt];
|
||||
List<Object?> get props => <Object?>[locationSharing, updatedAt];
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ import '../repositories/privacy_settings_repository_interface.dart';
|
||||
|
||||
/// Use case to retrieve privacy policy
|
||||
class GetPrivacyPolicyUseCase {
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
GetPrivacyPolicyUseCase(this._repository);
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
/// Execute the use case to get privacy policy
|
||||
Future<String> call() async {
|
||||
|
||||
@@ -2,9 +2,9 @@ import '../repositories/privacy_settings_repository_interface.dart';
|
||||
|
||||
/// Use case to retrieve the current staff member's profile visibility setting
|
||||
class GetProfileVisibilityUseCase {
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
GetProfileVisibilityUseCase(this._repository);
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
/// Execute the use case to get profile visibility status
|
||||
/// Returns true if profile is visible, false if hidden
|
||||
|
||||
@@ -2,9 +2,9 @@ import '../repositories/privacy_settings_repository_interface.dart';
|
||||
|
||||
/// Use case to retrieve terms of service
|
||||
class GetTermsUseCase {
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
GetTermsUseCase(this._repository);
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
/// Execute the use case to get terms of service
|
||||
Future<String> call() async {
|
||||
|
||||
@@ -4,10 +4,10 @@ import '../repositories/privacy_settings_repository_interface.dart';
|
||||
|
||||
/// Parameters for updating profile visibility
|
||||
class UpdateProfileVisibilityParams extends Equatable {
|
||||
/// Whether to show (true) or hide (false) the profile
|
||||
final bool isVisible;
|
||||
|
||||
const UpdateProfileVisibilityParams({required this.isVisible});
|
||||
/// Whether to show (true) or hide (false) the profile
|
||||
final bool isVisible;
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[isVisible];
|
||||
@@ -15,9 +15,9 @@ class UpdateProfileVisibilityParams extends Equatable {
|
||||
|
||||
/// Use case to update profile visibility setting
|
||||
class UpdateProfileVisibilityUseCase {
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
UpdateProfileVisibilityUseCase(this._repository);
|
||||
final PrivacySettingsRepositoryInterface _repository;
|
||||
|
||||
/// Execute the use case to update profile visibility
|
||||
/// Returns the updated visibility status
|
||||
|
||||
@@ -4,15 +4,15 @@ import '../../../domain/usecases/get_privacy_policy_usecase.dart';
|
||||
|
||||
/// State for Privacy Policy cubit
|
||||
class PrivacyPolicyState {
|
||||
final String? content;
|
||||
final bool isLoading;
|
||||
final String? error;
|
||||
|
||||
const PrivacyPolicyState({
|
||||
this.content,
|
||||
this.isLoading = false,
|
||||
this.error,
|
||||
});
|
||||
final String? content;
|
||||
final bool isLoading;
|
||||
final String? error;
|
||||
|
||||
PrivacyPolicyState copyWith({
|
||||
String? content,
|
||||
@@ -29,12 +29,12 @@ class PrivacyPolicyState {
|
||||
|
||||
/// Cubit for managing Privacy Policy content
|
||||
class PrivacyPolicyCubit extends Cubit<PrivacyPolicyState> {
|
||||
final GetPrivacyPolicyUseCase _getPrivacyPolicyUseCase;
|
||||
|
||||
PrivacyPolicyCubit({
|
||||
required GetPrivacyPolicyUseCase getPrivacyPolicyUseCase,
|
||||
}) : _getPrivacyPolicyUseCase = getPrivacyPolicyUseCase,
|
||||
super(const PrivacyPolicyState());
|
||||
final GetPrivacyPolicyUseCase _getPrivacyPolicyUseCase;
|
||||
|
||||
/// Fetch privacy policy content
|
||||
Future<void> fetchPrivacyPolicy() async {
|
||||
|
||||
@@ -4,15 +4,15 @@ import '../../../domain/usecases/get_terms_usecase.dart';
|
||||
|
||||
/// State for Terms of Service cubit
|
||||
class TermsState {
|
||||
final String? content;
|
||||
final bool isLoading;
|
||||
final String? error;
|
||||
|
||||
const TermsState({
|
||||
this.content,
|
||||
this.isLoading = false,
|
||||
this.error,
|
||||
});
|
||||
final String? content;
|
||||
final bool isLoading;
|
||||
final String? error;
|
||||
|
||||
TermsState copyWith({
|
||||
String? content,
|
||||
@@ -29,12 +29,12 @@ class TermsState {
|
||||
|
||||
/// Cubit for managing Terms of Service content
|
||||
class TermsCubit extends Cubit<TermsState> {
|
||||
final GetTermsUseCase _getTermsUseCase;
|
||||
|
||||
TermsCubit({
|
||||
required GetTermsUseCase getTermsUseCase,
|
||||
}) : _getTermsUseCase = getTermsUseCase,
|
||||
super(const TermsState());
|
||||
final GetTermsUseCase _getTermsUseCase;
|
||||
|
||||
/// Fetch terms of service content
|
||||
Future<void> fetchTerms() async {
|
||||
|
||||
@@ -12,10 +12,6 @@ part 'privacy_security_state.dart';
|
||||
/// BLoC managing privacy and security settings state
|
||||
class PrivacySecurityBloc
|
||||
extends Bloc<PrivacySecurityEvent, PrivacySecurityState> {
|
||||
final GetProfileVisibilityUseCase _getProfileVisibilityUseCase;
|
||||
final UpdateProfileVisibilityUseCase _updateProfileVisibilityUseCase;
|
||||
final GetTermsUseCase _getTermsUseCase;
|
||||
final GetPrivacyPolicyUseCase _getPrivacyPolicyUseCase;
|
||||
|
||||
PrivacySecurityBloc({
|
||||
required GetProfileVisibilityUseCase getProfileVisibilityUseCase,
|
||||
@@ -33,6 +29,10 @@ class PrivacySecurityBloc
|
||||
on<FetchPrivacyPolicyEvent>(_onFetchPrivacyPolicy);
|
||||
on<ClearProfileVisibilityUpdatedEvent>(_onClearProfileVisibilityUpdated);
|
||||
}
|
||||
final GetProfileVisibilityUseCase _getProfileVisibilityUseCase;
|
||||
final UpdateProfileVisibilityUseCase _updateProfileVisibilityUseCase;
|
||||
final GetTermsUseCase _getTermsUseCase;
|
||||
final GetPrivacyPolicyUseCase _getPrivacyPolicyUseCase;
|
||||
|
||||
Future<void> _onFetchProfileVisibility(
|
||||
FetchProfileVisibilityEvent event,
|
||||
|
||||
@@ -15,10 +15,10 @@ class FetchProfileVisibilityEvent extends PrivacySecurityEvent {
|
||||
|
||||
/// Event to update profile visibility
|
||||
class UpdateProfileVisibilityEvent extends PrivacySecurityEvent {
|
||||
/// Whether to show (true) or hide (false) the profile
|
||||
final bool isVisible;
|
||||
|
||||
const UpdateProfileVisibilityEvent({required this.isVisible});
|
||||
/// Whether to show (true) or hide (false) the profile
|
||||
final bool isVisible;
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[isVisible];
|
||||
|
||||
@@ -2,6 +2,18 @@ part of 'privacy_security_bloc.dart';
|
||||
|
||||
/// State for privacy security BLoC
|
||||
class PrivacySecurityState extends Equatable {
|
||||
|
||||
const PrivacySecurityState({
|
||||
this.isProfileVisible = true,
|
||||
this.isLoading = false,
|
||||
this.isUpdating = false,
|
||||
this.profileVisibilityUpdated = false,
|
||||
this.termsContent,
|
||||
this.isLoadingTerms = false,
|
||||
this.privacyPolicyContent,
|
||||
this.isLoadingPrivacyPolicy = false,
|
||||
this.error,
|
||||
});
|
||||
/// Current profile visibility setting (true = visible, false = hidden)
|
||||
final bool isProfileVisible;
|
||||
|
||||
@@ -29,18 +41,6 @@ class PrivacySecurityState extends Equatable {
|
||||
/// Error message, if any
|
||||
final String? error;
|
||||
|
||||
const PrivacySecurityState({
|
||||
this.isProfileVisible = true,
|
||||
this.isLoading = false,
|
||||
this.isUpdating = false,
|
||||
this.profileVisibilityUpdated = false,
|
||||
this.termsContent,
|
||||
this.isLoadingTerms = false,
|
||||
this.privacyPolicyContent,
|
||||
this.isLoadingPrivacyPolicy = false,
|
||||
this.error,
|
||||
});
|
||||
|
||||
/// Create a copy with optional field overrides
|
||||
PrivacySecurityState copyWith({
|
||||
bool? isProfileVisible,
|
||||
|
||||
@@ -9,8 +9,8 @@ import '../../blocs/legal/privacy_policy_cubit.dart';
|
||||
/// Page displaying the Privacy Policy document
|
||||
class PrivacyPolicyPage extends StatelessWidget {
|
||||
const PrivacyPolicyPage({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -9,8 +9,8 @@ import '../../blocs/legal/terms_cubit.dart';
|
||||
/// Page displaying the Terms of Service document
|
||||
class TermsOfServicePage extends StatelessWidget {
|
||||
const TermsOfServicePage({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -3,6 +3,13 @@ import 'package:design_system/design_system.dart';
|
||||
|
||||
/// Reusable widget for action tile (tap to navigate)
|
||||
class SettingsActionTile extends StatelessWidget {
|
||||
|
||||
const SettingsActionTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
required this.onTap,
|
||||
});
|
||||
/// The title of the action
|
||||
final String title;
|
||||
|
||||
@@ -12,13 +19,6 @@ class SettingsActionTile extends StatelessWidget {
|
||||
/// Callback when tile is tapped
|
||||
final VoidCallback onTap;
|
||||
|
||||
const SettingsActionTile({
|
||||
Key? key,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
required this.onTap,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
@@ -39,7 +39,7 @@ class SettingsActionTile extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
if (subtitle != null) ...<Widget>[
|
||||
SizedBox(height: UiConstants.space1),
|
||||
const SizedBox(height: UiConstants.space1),
|
||||
Text(
|
||||
subtitle!,
|
||||
style: UiTypography.footnote1r.copyWith(
|
||||
|
||||
@@ -3,11 +3,11 @@ import 'package:design_system/design_system.dart';
|
||||
|
||||
/// Divider widget for separating items within settings sections
|
||||
class SettingsDivider extends StatelessWidget {
|
||||
const SettingsDivider({Key? key}) : super(key: key);
|
||||
const SettingsDivider({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Divider(
|
||||
return const Divider(
|
||||
height: 1,
|
||||
color: UiColors.border,
|
||||
);
|
||||
|
||||
@@ -3,18 +3,18 @@ import 'package:design_system/design_system.dart';
|
||||
|
||||
/// Reusable widget for settings section header with icon
|
||||
class SettingsSectionHeader extends StatelessWidget {
|
||||
|
||||
const SettingsSectionHeader({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.icon,
|
||||
});
|
||||
/// The title of the section
|
||||
final String title;
|
||||
|
||||
/// The icon to display next to the title
|
||||
final IconData icon;
|
||||
|
||||
const SettingsSectionHeader({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.icon,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
@@ -24,7 +24,7 @@ class SettingsSectionHeader extends StatelessWidget {
|
||||
size: 20,
|
||||
color: UiColors.primary,
|
||||
),
|
||||
SizedBox(width: UiConstants.space2),
|
||||
const SizedBox(width: UiConstants.space2),
|
||||
Text(
|
||||
title,
|
||||
style: UiTypography.body1r.copyWith(
|
||||
|
||||
@@ -3,6 +3,14 @@ import 'package:design_system/design_system.dart';
|
||||
|
||||
/// Reusable widget for toggle tile in privacy settings
|
||||
class SettingsSwitchTile extends StatelessWidget {
|
||||
|
||||
const SettingsSwitchTile({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
});
|
||||
/// The title of the setting
|
||||
final String title;
|
||||
|
||||
@@ -15,14 +23,6 @@ class SettingsSwitchTile extends StatelessWidget {
|
||||
/// Callback when toggle is changed
|
||||
final ValueChanged<bool> onChanged;
|
||||
|
||||
const SettingsSwitchTile({
|
||||
Key? key,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
|
||||
Reference in New Issue
Block a user