393 lines
11 KiB
Dart
393 lines
11 KiB
Dart
import '../models/compliance.dart';
|
|
import '../models/shift.dart';
|
|
import '../models/timecard.dart';
|
|
|
|
/// Demo content. Everything is anchored to "now" so the app is live whenever
|
|
/// it is opened: the next shift always starts in 41 minutes.
|
|
abstract final class Seed {
|
|
static DateTime get _now => DateTime.now();
|
|
|
|
static DateTime _at(int dayOffset, int hour, int minute) {
|
|
final base = _now.add(Duration(days: dayOffset));
|
|
return DateTime(base.year, base.month, base.day, hour, minute);
|
|
}
|
|
|
|
static const _baristaReqs = [
|
|
'Government ID',
|
|
'Food handler certification',
|
|
'Black pants',
|
|
'Black shirt',
|
|
'Non-slip black shoes',
|
|
];
|
|
|
|
static List<Shift> shifts() {
|
|
final now = _now;
|
|
// Inside the 30-minute clock-in window, so the app opens on a shift you
|
|
// can actually start.
|
|
final soon = now.add(const Duration(minutes: 20));
|
|
return [
|
|
// Today: the shift you are about to clock into.
|
|
Shift(
|
|
id: 's1',
|
|
role: 'Barista',
|
|
business: 'Zoox',
|
|
venue: 'Zoox - San Jose Hub',
|
|
address: '848 E Gish Rd, San Jose CA',
|
|
start: soon,
|
|
end: soon.add(const Duration(hours: 6)),
|
|
rate: 21.00,
|
|
status: ShiftStatus.booked,
|
|
distanceMiles: 2.4,
|
|
manager: 'Kirk R. - Owner',
|
|
requirements: _baristaReqs,
|
|
),
|
|
Shift(
|
|
id: 's2',
|
|
role: 'Server',
|
|
business: 'Google LLC',
|
|
venue: 'Google LLC - Midpoint',
|
|
address: 'Midpoint, Sunnyvale CA',
|
|
start: _at(1, 13, 0),
|
|
end: _at(1, 18, 0),
|
|
rate: 24.00,
|
|
status: ShiftStatus.booked,
|
|
distanceMiles: 3.1,
|
|
manager: 'Dana W. - Floor lead',
|
|
requirements: _baristaReqs,
|
|
),
|
|
// Open market, highest paying first.
|
|
Shift(
|
|
id: 's3',
|
|
role: 'Bartender',
|
|
business: 'Google LLC',
|
|
venue: 'Google LLC - Midpoint',
|
|
address: 'Midpoint, Sunnyvale CA',
|
|
start: _at(2, 16, 0),
|
|
end: _at(2, 23, 0),
|
|
rate: 28.00,
|
|
status: ShiftStatus.open,
|
|
distanceMiles: 3.1,
|
|
requirements: [..._baristaReqs, 'Responsible beverage service'],
|
|
),
|
|
Shift(
|
|
id: 's4',
|
|
role: 'Barista',
|
|
business: 'Zoox',
|
|
venue: 'Zoox - San Jose Hub',
|
|
address: '848 E Gish Rd, San Jose CA',
|
|
start: _at(3, 18, 0),
|
|
end: _at(3, 23, 50),
|
|
rate: 21.00,
|
|
status: ShiftStatus.open,
|
|
distanceMiles: 2.4,
|
|
requirements: _baristaReqs,
|
|
),
|
|
Shift(
|
|
id: 's5',
|
|
role: 'Host',
|
|
business: 'Google LLC',
|
|
venue: 'Google LLC - Midpoint',
|
|
address: 'Midpoint, Sunnyvale CA',
|
|
start: _at(4, 11, 0),
|
|
end: _at(4, 17, 0),
|
|
rate: 19.50,
|
|
status: ShiftStatus.open,
|
|
distanceMiles: 3.1,
|
|
requirements: _baristaReqs,
|
|
),
|
|
Shift(
|
|
id: 's6',
|
|
role: 'Banquet server',
|
|
business: 'Legendary Events',
|
|
venue: 'Legendary Events - Convention Centre',
|
|
address: '150 W San Carlos St, San Jose CA',
|
|
start: _at(5, 9, 0),
|
|
end: _at(5, 17, 30),
|
|
rate: 22.50,
|
|
status: ShiftStatus.open,
|
|
distanceMiles: 4.8,
|
|
requirements: _baristaReqs,
|
|
),
|
|
// Worked history.
|
|
Shift(
|
|
id: 's7',
|
|
role: 'Barista',
|
|
business: 'Zoox',
|
|
venue: 'Zoox - San Jose Hub',
|
|
address: '848 E Gish Rd, San Jose CA',
|
|
start: _at(-4, 17, 50),
|
|
end: _at(-4, 23, 50),
|
|
rate: 21.00,
|
|
status: ShiftStatus.completed,
|
|
distanceMiles: 2.4,
|
|
clockIn: _at(-4, 18, 1),
|
|
clockOut: _at(-4, 23, 50),
|
|
requirements: _baristaReqs,
|
|
),
|
|
Shift(
|
|
id: 's8',
|
|
role: 'Barista',
|
|
business: 'Google LLC',
|
|
venue: 'Google LLC - Midpoint',
|
|
address: 'Midpoint, Sunnyvale CA',
|
|
start: _at(-6, 11, 0),
|
|
end: _at(-6, 18, 0),
|
|
rate: 21.00,
|
|
status: ShiftStatus.cancelled,
|
|
distanceMiles: 3.1,
|
|
requirements: _baristaReqs,
|
|
),
|
|
Shift(
|
|
id: 's9',
|
|
role: 'Barista',
|
|
business: 'Google LLC',
|
|
venue: 'Google LLC - Midpoint',
|
|
address: 'Midpoint, Sunnyvale CA',
|
|
start: _at(-13, 9, 0),
|
|
end: _at(-13, 15, 0),
|
|
rate: 21.00,
|
|
status: ShiftStatus.noShow,
|
|
distanceMiles: 3.1,
|
|
requirements: _baristaReqs,
|
|
),
|
|
];
|
|
}
|
|
|
|
static List<Timecard> timecards() {
|
|
final worked = shifts().firstWhere((s) => s.id == 's7');
|
|
return [
|
|
Timecard(
|
|
id: 'tc1',
|
|
shiftId: worked.id,
|
|
role: worked.role,
|
|
business: worked.business,
|
|
scheduledStart: worked.start,
|
|
scheduledEnd: worked.end,
|
|
clockIn: worked.clockIn!,
|
|
clockOut: worked.clockOut!,
|
|
breakMinutes: worked.breakMinutes,
|
|
rate: worked.rate,
|
|
status: TimecardStatus.needsReview,
|
|
submittedAt: worked.clockOut!.add(const Duration(minutes: 12)),
|
|
),
|
|
];
|
|
}
|
|
|
|
static List<ComplianceItem> documents() => [
|
|
ComplianceItem(
|
|
id: 'd1',
|
|
title: 'Government ID',
|
|
subtitle: 'State ID or passport',
|
|
state: ComplianceState.verified,
|
|
fileName: 'government-id-front.jpg',
|
|
fileMeta: '2.1 MB - uploaded 2 Aug',
|
|
expires: DateTime(2029, 3, 14),
|
|
),
|
|
ComplianceItem(
|
|
id: 'd2',
|
|
title: 'Social security',
|
|
subtitle: 'Card or SSA letter',
|
|
state: ComplianceState.verified,
|
|
fileName: 'ssn-card.jpg',
|
|
fileMeta: '1.2 MB - uploaded 2 Aug',
|
|
),
|
|
ComplianceItem(
|
|
id: 'd3',
|
|
title: 'Work permit',
|
|
subtitle: 'Right-to-work evidence',
|
|
state: ComplianceState.verified,
|
|
fileName: 'work-permit.pdf',
|
|
fileMeta: '640 KB - uploaded 2 Aug',
|
|
),
|
|
ComplianceItem(
|
|
id: 'd4',
|
|
title: 'Proof of address',
|
|
subtitle: 'Bill or statement, last 90 days',
|
|
state: ComplianceState.pending,
|
|
statusLabel: 'In review',
|
|
fileName: 'utility-bill.pdf',
|
|
fileMeta: '380 KB - uploaded yesterday',
|
|
),
|
|
];
|
|
|
|
static List<ComplianceItem> certificates() => [
|
|
ComplianceItem(
|
|
id: 'c1',
|
|
title: 'Food handler certification',
|
|
subtitle: 'Accepted by all California venues',
|
|
state: ComplianceState.verified,
|
|
statusLabel: 'Validated',
|
|
fileName: 'food-safety-certificate.pdf',
|
|
fileMeta: '840 KB - uploaded 2 Aug',
|
|
expires: DateTime(2027, 3, 14),
|
|
),
|
|
ComplianceItem(
|
|
id: 'c2',
|
|
title: 'Responsible beverage service',
|
|
subtitle: 'Needed for bartender shifts',
|
|
state: ComplianceState.verified,
|
|
statusLabel: 'Validated',
|
|
fileName: 'rbs-certificate.pdf',
|
|
fileMeta: '510 KB - uploaded 2 Aug',
|
|
expires: DateTime(2028, 1, 9),
|
|
),
|
|
ComplianceItem(
|
|
id: 'c3',
|
|
title: 'CPR / AED',
|
|
subtitle: 'Adds around 4 shifts a week near you',
|
|
state: ComplianceState.missing,
|
|
statusLabel: 'Not added',
|
|
required_: false,
|
|
),
|
|
ComplianceItem(
|
|
id: 'c4',
|
|
title: 'Forklift licence',
|
|
subtitle: 'Warehouse and logistics roles',
|
|
state: ComplianceState.missing,
|
|
statusLabel: 'Not added',
|
|
required_: false,
|
|
),
|
|
];
|
|
|
|
static List<ComplianceItem> taxForms() => [
|
|
ComplianceItem(
|
|
id: 't1',
|
|
title: 'Form I-9',
|
|
subtitle: 'Employment eligibility verification',
|
|
state: ComplianceState.verified,
|
|
statusLabel: 'Approved',
|
|
fileName: 'i9-form.pdf',
|
|
fileMeta: 'Approved 3 Aug',
|
|
),
|
|
ComplianceItem(
|
|
id: 't2',
|
|
title: 'Form W-4',
|
|
subtitle: 'Sets how much tax is withheld',
|
|
state: ComplianceState.verified,
|
|
statusLabel: 'Approved',
|
|
fileName: 'w4-form.pdf',
|
|
fileMeta: 'Approved 3 Aug',
|
|
),
|
|
];
|
|
|
|
static List<ComplianceItem> wardrobe() => [
|
|
ComplianceItem(
|
|
id: 'w1',
|
|
title: 'Black pants',
|
|
subtitle: 'Solid black dress pants or slacks',
|
|
state: ComplianceState.verified,
|
|
statusLabel: 'Approved',
|
|
fileName: 'black-pants.jpg',
|
|
fileMeta: '1.4 MB - uploaded 2 Aug',
|
|
),
|
|
ComplianceItem(
|
|
id: 'w2',
|
|
title: 'Black shirt',
|
|
subtitle: 'Plain, no logos',
|
|
state: ComplianceState.verified,
|
|
statusLabel: 'Approved',
|
|
fileName: 'black-shirt.jpg',
|
|
fileMeta: '1.1 MB - uploaded 2 Aug',
|
|
),
|
|
ComplianceItem(
|
|
id: 'w3',
|
|
title: 'Non-slip black shoes',
|
|
subtitle: 'Closed-toe, required on every shift',
|
|
state: ComplianceState.verified,
|
|
statusLabel: 'Approved',
|
|
fileName: 'black-shoes.jpg',
|
|
fileMeta: '0.9 MB - uploaded 2 Aug',
|
|
),
|
|
ComplianceItem(
|
|
id: 'w4',
|
|
title: 'Black belt',
|
|
subtitle: 'Plain, simple buckle',
|
|
state: ComplianceState.missing,
|
|
statusLabel: 'Not added',
|
|
required_: false,
|
|
),
|
|
];
|
|
|
|
static const workSettings = <String>[
|
|
'Hospitality',
|
|
'Restaurant',
|
|
'Warehouse',
|
|
'Logistics',
|
|
'Events',
|
|
'Stadiums',
|
|
'Education',
|
|
'Healthcare & cafeteria',
|
|
'Convention centre',
|
|
'Catering',
|
|
];
|
|
|
|
static const skills = <String>[
|
|
'Food prep',
|
|
'Cooking',
|
|
'Grilling',
|
|
'Dishwashing',
|
|
'Food service',
|
|
'Banquet',
|
|
'Bartender',
|
|
'Barista',
|
|
'Customer service',
|
|
'Safe food handling',
|
|
'Event setup',
|
|
];
|
|
|
|
static const supportTopics = <String>[
|
|
'Shift issue',
|
|
'Pay or billing',
|
|
'Schedule clash',
|
|
'Account',
|
|
'Bug report',
|
|
'Feature idea',
|
|
];
|
|
|
|
static const faqs = <String, List<(String, String)>>{
|
|
'Getting started': [
|
|
(
|
|
'How do I finish my worker profile?',
|
|
'Open Profile, then Compliance. Work down the sections until every one '
|
|
'shows a green tick. You can accept shifts as soon as documents, '
|
|
'tax forms and attire are complete.',
|
|
),
|
|
(
|
|
"Why can't I apply to shifts yet?",
|
|
'Businesses only see workers who are fully compliant. Anything still '
|
|
'marked yellow on the compliance hub is blocking you.',
|
|
),
|
|
],
|
|
'Shifts and attendance': [
|
|
(
|
|
'How does clock-in work?',
|
|
'The clock-in button unlocks 30 minutes before your shift starts, once '
|
|
'you are within 150 m of the venue. Tap out when you leave and the '
|
|
'timecard submits itself.',
|
|
),
|
|
(
|
|
'What happens if I request a swap?',
|
|
'Your shift is offered to other qualified workers. You stay responsible '
|
|
'for it until someone accepts, so keep an eye on notifications.',
|
|
),
|
|
(
|
|
'What counts as a no-show?',
|
|
'Not clocking in within 30 minutes of the scheduled start, with no '
|
|
'cancellation. No-shows cost 15 points of trust index each.',
|
|
),
|
|
],
|
|
'Pay and compliance': [
|
|
(
|
|
'When do I actually get paid?',
|
|
'Semi-monthly. Each period closes on the 15th and the last day of the '
|
|
'month, and pays 11 days later.',
|
|
),
|
|
(
|
|
'How are documents verified?',
|
|
'A reviewer checks each upload by hand, usually within one business '
|
|
'day. You get a notification either way.',
|
|
),
|
|
],
|
|
};
|
|
}
|