Initial commit: Krow Worker App
This commit is contained in:
168
lib/state/profile_controller.dart
Normal file
168
lib/state/profile_controller.dart
Normal file
@@ -0,0 +1,168 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../models/compliance.dart';
|
||||
import '../models/shift.dart';
|
||||
import '../models/worker.dart';
|
||||
import 'session_controller.dart';
|
||||
import 'shifts_controller.dart';
|
||||
|
||||
class ProfileState {
|
||||
const ProfileState({
|
||||
required this.worker,
|
||||
required this.settings,
|
||||
required this.skills,
|
||||
required this.contacts,
|
||||
this.bank,
|
||||
this.newsletter = false,
|
||||
});
|
||||
|
||||
final Worker worker;
|
||||
|
||||
/// Settings the worker has worked in, and the trades they can do.
|
||||
final Set<String> settings;
|
||||
final Set<String> skills;
|
||||
final List<EmergencyContact> contacts;
|
||||
final BankAccount? bank;
|
||||
final bool newsletter;
|
||||
|
||||
ProfileState copyWith({
|
||||
Worker? worker,
|
||||
Set<String>? settings,
|
||||
Set<String>? skills,
|
||||
List<EmergencyContact>? contacts,
|
||||
BankAccount? bank,
|
||||
bool? newsletter,
|
||||
}) => ProfileState(
|
||||
worker: worker ?? this.worker,
|
||||
settings: settings ?? this.settings,
|
||||
skills: skills ?? this.skills,
|
||||
contacts: contacts ?? this.contacts,
|
||||
bank: bank ?? this.bank,
|
||||
newsletter: newsletter ?? this.newsletter,
|
||||
);
|
||||
}
|
||||
|
||||
class ProfileController extends Notifier<ProfileState> {
|
||||
static const _kSettings = 'profile_settings';
|
||||
static const _kSkills = 'profile_skills';
|
||||
static const _kNewsletter = 'profile_newsletter';
|
||||
static const _kName = 'profile_name';
|
||||
|
||||
SharedPreferences get _prefs => ref.read(prefsProvider);
|
||||
|
||||
@override
|
||||
ProfileState build() {
|
||||
final p = _prefs;
|
||||
final phone = ref.watch(sessionProvider).phone;
|
||||
return ProfileState(
|
||||
worker: Worker(
|
||||
name: p.getString(_kName) ?? 'Iliana Ortega',
|
||||
role: 'Barista',
|
||||
city: 'San Jose',
|
||||
phone: phone ?? '+1 408 555 0148',
|
||||
onTimePercent: 50,
|
||||
noShows: 1,
|
||||
cancellations: 1,
|
||||
),
|
||||
settings:
|
||||
(p.getStringList(_kSettings) ??
|
||||
const ['Hospitality', 'Events', 'Catering'])
|
||||
.toSet(),
|
||||
skills:
|
||||
(p.getStringList(_kSkills) ??
|
||||
const ['Barista', 'Customer service', 'Food service'])
|
||||
.toSet(),
|
||||
contacts: [
|
||||
EmergencyContact(
|
||||
name: 'Carlos Ortega',
|
||||
phone: '+1 555 001 0006',
|
||||
relationship: 'Spouse',
|
||||
),
|
||||
],
|
||||
newsletter: p.getBool(_kNewsletter) ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
void updateName(String name) {
|
||||
_prefs.setString(_kName, name);
|
||||
state = state.copyWith(worker: state.worker.copyWith(name: name));
|
||||
}
|
||||
|
||||
void toggleSetting(String value) {
|
||||
final next = {...state.settings};
|
||||
if (!next.remove(value)) next.add(value);
|
||||
_prefs.setStringList(_kSettings, next.toList());
|
||||
state = state.copyWith(settings: next);
|
||||
}
|
||||
|
||||
void toggleSkill(String value) {
|
||||
final next = {...state.skills};
|
||||
if (!next.remove(value)) next.add(value);
|
||||
_prefs.setStringList(_kSkills, next.toList());
|
||||
state = state.copyWith(skills: next);
|
||||
}
|
||||
|
||||
void addSkill(String value) {
|
||||
final trimmed = value.trim();
|
||||
if (trimmed.isEmpty) return;
|
||||
final next = {...state.skills, trimmed};
|
||||
_prefs.setStringList(_kSkills, next.toList());
|
||||
state = state.copyWith(skills: next);
|
||||
}
|
||||
|
||||
void saveContact(EmergencyContact contact, {int? index}) {
|
||||
final next = [...state.contacts];
|
||||
if (index != null && index < next.length) {
|
||||
next[index] = contact;
|
||||
} else {
|
||||
next.add(contact);
|
||||
}
|
||||
state = state.copyWith(contacts: next);
|
||||
}
|
||||
|
||||
void removeContact(int index) {
|
||||
final next = [...state.contacts]..removeAt(index);
|
||||
state = state.copyWith(contacts: next);
|
||||
}
|
||||
|
||||
void saveBank(BankAccount account) {
|
||||
state = state.copyWith(bank: account);
|
||||
}
|
||||
|
||||
void setNewsletter(bool value) {
|
||||
_prefs.setBool(_kNewsletter, value);
|
||||
state = state.copyWith(newsletter: value);
|
||||
}
|
||||
}
|
||||
|
||||
final profileProvider = NotifierProvider<ProfileController, ProfileState>(
|
||||
ProfileController.new,
|
||||
);
|
||||
|
||||
/// Live stats derived from the shift list, so the profile reflects what the
|
||||
/// worker has actually done in this session.
|
||||
final workerStatsProvider = Provider<Worker>((ref) {
|
||||
final base = ref.watch(profileProvider).worker;
|
||||
final shifts = ref.watch(shiftsProvider);
|
||||
final completed = shifts
|
||||
.where((s) => s.status == ShiftStatus.completed)
|
||||
.toList();
|
||||
final noShows = shifts.where((s) => s.status == ShiftStatus.noShow).length;
|
||||
final cancels = shifts.where((s) => s.status == ShiftStatus.cancelled).length;
|
||||
final onTime = completed
|
||||
.where(
|
||||
(s) =>
|
||||
s.clockIn != null &&
|
||||
!s.clockIn!.isAfter(s.start.add(const Duration(minutes: 5))),
|
||||
)
|
||||
.length;
|
||||
return base.copyWith(
|
||||
shiftsWorked: completed.length,
|
||||
onTimePercent: completed.isEmpty
|
||||
? 100
|
||||
: (onTime * 100 / completed.length).round(),
|
||||
noShows: noShows,
|
||||
cancellations: cancels,
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user