All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m8s
- Implemented routine child-mode flow tests to ensure proper functionality of routine assignment and task completion. - Created notification tests for parent view to verify routine completion notifications for children. - Developed ChildRoutineOverlay component for displaying routine tasks and handling user interactions. - Added RoutineApproveDialog component for approving or rejecting completed routines. - Created unit tests for ChildRoutineOverlay and RoutineEditView components to ensure correct behavior and rendering. - Enhanced RoutineEditView with proper handling of task addition and form submission. Co-authored-by: Copilot <copilot@github.com>
388 lines
8.5 KiB
TypeScript
388 lines
8.5 KiB
TypeScript
export type TaskType = 'chore' | 'kindness' | 'penalty'
|
||
|
||
export interface Task {
|
||
id: string
|
||
name: string
|
||
points: number
|
||
type: TaskType
|
||
image_id: string | null
|
||
image_url?: string | null // optional, for resolved URLs
|
||
}
|
||
export const TASK_FIELDS = ['id', 'name', 'points', 'type', 'image_id'] as const
|
||
|
||
export interface DayConfig {
|
||
day: number // 0=Sun, 1=Mon, ..., 6=Sat
|
||
hour: number // 0–23 (24h)
|
||
minute: number // 0, 15, 30, or 45
|
||
}
|
||
|
||
export interface ChoreSchedule {
|
||
id: string
|
||
child_id: string
|
||
task_id: string
|
||
mode: 'days' | 'interval'
|
||
// mode='days'
|
||
day_configs: DayConfig[]
|
||
default_hour?: number // master deadline hour; present when mode='days'
|
||
default_minute?: number // master deadline minute; present when mode='days'
|
||
default_has_deadline?: boolean // false = 'Anytime', no expiry for 'days' mode
|
||
// mode='interval'
|
||
interval_days: number // 1–7
|
||
anchor_date: string // ISO date string e.g. "2026-02-25"; "" means use today
|
||
interval_has_deadline: boolean // false = "Anytime" (no deadline)
|
||
interval_hour: number
|
||
interval_minute: number
|
||
enabled?: boolean // false = schedule paused; chore won't appear for child
|
||
created_at: number
|
||
updated_at: number
|
||
}
|
||
|
||
export interface Routine {
|
||
id: string
|
||
name: string
|
||
points: number
|
||
image_id: string | null
|
||
image_url?: string | null
|
||
}
|
||
export const ROUTINE_FIELDS = ['id', 'name', 'points', 'image_id'] as const
|
||
|
||
export interface RoutineItem {
|
||
id: string
|
||
routine_id: string
|
||
name: string
|
||
image_id: string | null
|
||
order: number
|
||
}
|
||
|
||
export interface RoutineSchedule {
|
||
id: string
|
||
child_id: string
|
||
routine_id: string
|
||
mode: 'days' | 'interval'
|
||
day_configs: DayConfig[]
|
||
default_hour?: number
|
||
default_minute?: number
|
||
default_has_deadline?: boolean
|
||
interval_days: number
|
||
anchor_date: string
|
||
interval_has_deadline: boolean
|
||
interval_hour: number
|
||
interval_minute: number
|
||
enabled?: boolean
|
||
created_at: number
|
||
updated_at: number
|
||
}
|
||
|
||
export interface ChildRoutine {
|
||
id: string
|
||
name: string
|
||
points: number
|
||
image_id: string | null
|
||
image_url?: string | null
|
||
custom_value?: number | null
|
||
schedule?: RoutineSchedule | null
|
||
extension_date?: string | null
|
||
pending_status?: 'pending' | 'approved' | null
|
||
approved_at?: string | null
|
||
pending_confirmation_id?: string | null
|
||
items: RoutineItem[]
|
||
}
|
||
|
||
export interface ChildTask {
|
||
id: string
|
||
name: string
|
||
type: TaskType
|
||
points: number
|
||
image_id: string | null
|
||
image_url?: string | null
|
||
custom_value?: number | null
|
||
schedule?: ChoreSchedule | null
|
||
extension_date?: string | null // ISO date of today's extension, if any
|
||
pending_status?: 'pending' | 'approved' | null
|
||
approved_at?: string | null
|
||
}
|
||
|
||
export interface User {
|
||
id: string
|
||
first_name: string
|
||
last_name: string
|
||
email: string
|
||
token_version: number
|
||
image_id: string | null
|
||
marked_for_deletion: boolean
|
||
marked_for_deletion_at: string | null
|
||
deletion_in_progress: boolean
|
||
deletion_attempted_at: string | null
|
||
role: string
|
||
timezone: string | null
|
||
email_digest_enabled: boolean
|
||
}
|
||
|
||
export interface Child {
|
||
id: string
|
||
name: string
|
||
age: number
|
||
tasks: string[]
|
||
routines?: string[]
|
||
rewards: string[]
|
||
points: number
|
||
image_id: string | null
|
||
image_url?: string | null // optional, for resolved URLs
|
||
}
|
||
export const CHILD_FIELDS = [
|
||
'id',
|
||
'name',
|
||
'age',
|
||
'tasks',
|
||
'routines',
|
||
'rewards',
|
||
'points',
|
||
'image_id',
|
||
] as const
|
||
|
||
export interface Reward {
|
||
id: string
|
||
name: string
|
||
cost: number
|
||
points_needed: number
|
||
image_id: string | null
|
||
image_url?: string | null // optional, for resolved URLs
|
||
}
|
||
export const REWARD_FIELDS = ['id', 'name', 'cost', 'points_needed', 'image_id'] as const
|
||
|
||
export interface RewardStatus {
|
||
id: string
|
||
name: string
|
||
points_needed: number
|
||
cost: number
|
||
redeeming: boolean
|
||
image_id: string | null
|
||
image_url?: string | null // optional, for resolved URLs
|
||
}
|
||
export const REWARD_STATUS_FIELDS = [
|
||
'id',
|
||
'name',
|
||
'points_needed',
|
||
'cost',
|
||
'redeeming',
|
||
'image_id',
|
||
] as const
|
||
|
||
export interface PendingConfirmation {
|
||
id: string
|
||
child_id: string
|
||
child_name: string
|
||
child_image_id: string | null
|
||
child_image_url?: string | null
|
||
entity_id: string
|
||
entity_type: 'chore' | 'reward' | 'routine'
|
||
entity_name: string
|
||
entity_image_id: string | null
|
||
entity_image_url?: string | null
|
||
status: 'pending' | 'approved' | 'rejected'
|
||
approved_at: string | null
|
||
}
|
||
export const PENDING_CONFIRMATION_FIELDS = [
|
||
'id',
|
||
'child_id',
|
||
'child_name',
|
||
'child_image_id',
|
||
'entity_id',
|
||
'entity_type',
|
||
'entity_name',
|
||
'entity_image_id',
|
||
'status',
|
||
'approved_at',
|
||
] as const
|
||
|
||
export interface Event {
|
||
type: string
|
||
payload:
|
||
| ChildModifiedEventPayload
|
||
| ChildTaskTriggeredEventPayload
|
||
| ChildRewardTriggeredEventPayload
|
||
| ChildRewardRequestEventPayload
|
||
| ChildTasksSetEventPayload
|
||
| ChildRewardsSetEventPayload
|
||
| TaskModifiedEventPayload
|
||
| RewardModifiedEventPayload
|
||
| TrackingEventCreatedPayload
|
||
| ChildOverrideSetPayload
|
||
| ChildOverrideDeletedPayload
|
||
| ChoreScheduleModifiedPayload
|
||
| ChoreTimeExtendedPayload
|
||
| ChildChoreConfirmationPayload
|
||
| RoutineModifiedEventPayload
|
||
| ChildRoutinesSetEventPayload
|
||
| RoutineScheduleModifiedPayload
|
||
| RoutineTimeExtendedPayload
|
||
| ChildRoutineConfirmationPayload
|
||
}
|
||
|
||
export interface ChildModifiedEventPayload {
|
||
child_id: string
|
||
operation: 'ADD' | 'DELETE' | 'EDIT'
|
||
}
|
||
|
||
export interface ChildTaskTriggeredEventPayload {
|
||
task_id: string
|
||
child_id: string
|
||
points: number
|
||
}
|
||
|
||
export interface ChildRewardTriggeredEventPayload {
|
||
task_id: string
|
||
child_id: string
|
||
points: number
|
||
}
|
||
|
||
export interface ChildRewardRequestEventPayload {
|
||
child_id: string
|
||
reward_id: string
|
||
operation: 'GRANTED' | 'CREATED' | 'CANCELLED'
|
||
}
|
||
|
||
export interface ChildTasksSetEventPayload {
|
||
child_id: string
|
||
task_ids: string[]
|
||
}
|
||
|
||
export interface ChildRewardsSetEventPayload {
|
||
child_id: string
|
||
reward_ids: string[]
|
||
}
|
||
export interface TaskModifiedEventPayload {
|
||
task_id: string
|
||
operation: 'ADD' | 'DELETE' | 'EDIT'
|
||
}
|
||
export interface RewardModifiedEventPayload {
|
||
reward_id: string
|
||
operation: 'ADD' | 'DELETE' | 'EDIT'
|
||
}
|
||
|
||
export interface RoutineModifiedEventPayload {
|
||
routine_id: string
|
||
operation: 'ADD' | 'DELETE' | 'EDIT'
|
||
}
|
||
|
||
export interface ChildRoutinesSetEventPayload {
|
||
child_id: string
|
||
routine_ids: string[]
|
||
}
|
||
|
||
export interface TrackingEventCreatedPayload {
|
||
tracking_event_id: string
|
||
child_id: string
|
||
entity_type: EntityType
|
||
action: ActionType
|
||
}
|
||
|
||
export interface ChildOverrideSetPayload {
|
||
override: ChildOverride
|
||
}
|
||
|
||
export interface ChildOverrideDeletedPayload {
|
||
child_id: string
|
||
entity_id: string
|
||
entity_type: string
|
||
}
|
||
|
||
export type EntityType = 'task' | 'reward' | 'penalty' | 'chore' | 'kindness' | 'routine'
|
||
export type ActionType =
|
||
| 'activated'
|
||
| 'requested'
|
||
| 'redeemed'
|
||
| 'cancelled'
|
||
| 'confirmed'
|
||
| 'approved'
|
||
| 'rejected'
|
||
| 'reset'
|
||
|
||
export interface TrackingEvent {
|
||
id: string
|
||
user_id: string | null
|
||
child_id: string
|
||
entity_type: EntityType
|
||
entity_id: string
|
||
action: ActionType
|
||
points_before: number
|
||
points_after: number
|
||
delta: number
|
||
occurred_at: string
|
||
created_at: number
|
||
updated_at: number
|
||
metadata?: Record<string, any> | null
|
||
}
|
||
|
||
export const TRACKING_EVENT_FIELDS = [
|
||
'id',
|
||
'user_id',
|
||
'child_id',
|
||
'entity_type',
|
||
'entity_id',
|
||
'action',
|
||
'points_before',
|
||
'points_after',
|
||
'delta',
|
||
'occurred_at',
|
||
'created_at',
|
||
'updated_at',
|
||
'metadata',
|
||
] as const
|
||
|
||
export type OverrideEntityType = 'task' | 'reward' | 'chore' | 'kindness' | 'penalty' | 'routine'
|
||
|
||
export interface ChildOverride {
|
||
id: string
|
||
child_id: string
|
||
entity_id: string
|
||
entity_type: OverrideEntityType
|
||
custom_value: number
|
||
created_at: number
|
||
updated_at: number
|
||
}
|
||
|
||
export const CHILD_OVERRIDE_FIELDS = [
|
||
'id',
|
||
'child_id',
|
||
'entity_id',
|
||
'entity_type',
|
||
'custom_value',
|
||
'created_at',
|
||
'updated_at',
|
||
] as const
|
||
|
||
export interface ChoreScheduleModifiedPayload {
|
||
child_id: string
|
||
task_id: string
|
||
operation: 'SET' | 'DELETED'
|
||
}
|
||
|
||
export interface ChoreTimeExtendedPayload {
|
||
child_id: string
|
||
task_id: string
|
||
}
|
||
|
||
export interface ChildChoreConfirmationPayload {
|
||
child_id: string
|
||
task_id: string
|
||
operation: 'CONFIRMED' | 'APPROVED' | 'REJECTED' | 'CANCELLED' | 'RESET'
|
||
}
|
||
|
||
export interface RoutineScheduleModifiedPayload {
|
||
child_id: string
|
||
routine_id: string
|
||
operation: 'SET' | 'DELETED'
|
||
}
|
||
|
||
export interface RoutineTimeExtendedPayload {
|
||
child_id: string
|
||
routine_id: string
|
||
}
|
||
|
||
export interface ChildRoutineConfirmationPayload {
|
||
child_id: string
|
||
routine_id: string
|
||
operation: 'PENDING' | 'APPROVED' | 'REJECTED' | 'RESET'
|
||
}
|