Merge branch 'feat/habit-stop-use-case' into 'develop'

feat: habit stop use case

See merge request rrll/p61-project!5
This commit is contained in:
Théo LUDWIG 2024-04-12 13:25:14 +00:00
commit 1a89fa03c5
7 changed files with 103 additions and 14 deletions

View File

@ -8,6 +8,7 @@ export const HabitSchema = EntitySchema.extend({
name: z.string().min(1).max(50), name: z.string().min(1).max(50),
color: z.string().min(4).max(9).regex(/^#/), color: z.string().min(4).max(9).regex(/^#/),
icon: z.string().min(1), icon: z.string().min(1),
endDate: z.date().optional(),
}) })
export const HabitCreateSchema = HabitSchema.extend({ export const HabitCreateSchema = HabitSchema.extend({
@ -29,7 +30,6 @@ export interface HabitData extends HabitBase {
export interface HabitJSON extends HabitBase { export interface HabitJSON extends HabitBase {
goal: GoalBaseJSON goal: GoalBaseJSON
startDate: string startDate: string
endDate?: string
} }
export class Habit extends Entity implements HabitData { export class Habit extends Entity implements HabitData {
@ -62,7 +62,7 @@ export class Habit extends Entity implements HabitData {
icon: this.icon, icon: this.icon,
goal: this.goal, goal: this.goal,
startDate: this.startDate.toISOString(), startDate: this.startDate.toISOString(),
endDate: this.endDate?.toISOString(), endDate: this?.endDate,
} }
} }
} }

View File

@ -0,0 +1,24 @@
import type { Habit } from "../entities/Habit"
import type { HabitEditRepository } from "../repositories/HabitEdit"
export interface HabitStopUseCaseDependencyOptions {
habitEditRepository: HabitEditRepository
}
export class HabitStopUseCase implements HabitStopUseCaseDependencyOptions {
public habitEditRepository: HabitEditRepository
public constructor(options: HabitStopUseCaseDependencyOptions) {
this.habitEditRepository = options.habitEditRepository
}
public async execute(habitToStop: Habit): Promise<Habit> {
const habit = await this.habitEditRepository.execute({
habitEditData: {
...habitToStop,
endDate: new Date(),
},
})
return habit
}
}

View File

@ -13,6 +13,7 @@ import { HabitEditUseCase } from "@/domain/use-cases/HabitEdit"
import { HabitProgressCreateSupabaseRepository } from "./supabase/repositories/HabitProgressCreate" import { HabitProgressCreateSupabaseRepository } from "./supabase/repositories/HabitProgressCreate"
import { HabitProgressUpdateSupabaseRepository } from "./supabase/repositories/HabitProgressUpdate" import { HabitProgressUpdateSupabaseRepository } from "./supabase/repositories/HabitProgressUpdate"
import { HabitGoalProgressUpdateUseCase } from "@/domain/use-cases/HabitGoalProgressUpdate" import { HabitGoalProgressUpdateUseCase } from "@/domain/use-cases/HabitGoalProgressUpdate"
import { HabitStopUseCase } from "@/domain/use-cases/HabitStop"
/** /**
* Repositories * Repositories
@ -64,6 +65,9 @@ const habitGoalProgressUpdateUseCase = new HabitGoalProgressUpdateUseCase({
habitProgressCreateRepository, habitProgressCreateRepository,
habitProgressUpdateRepository, habitProgressUpdateRepository,
}) })
const habitStopUseCase = new HabitStopUseCase({
habitEditRepository,
})
/** /**
* Presenters * Presenters
@ -75,5 +79,6 @@ export const habitsTrackerPresenter = new HabitsTrackerPresenter({
retrieveHabitsTrackerUseCase, retrieveHabitsTrackerUseCase,
habitCreateUseCase, habitCreateUseCase,
habitEditUseCase, habitEditUseCase,
habitStopUseCase,
habitGoalProgressUpdateUseCase, habitGoalProgressUpdateUseCase,
}) })

View File

@ -15,6 +15,7 @@ export class HabitEditSupabaseRepository
name: habitEditData.name, name: habitEditData.name,
color: habitEditData.color, color: habitEditData.color,
icon: habitEditData.icon, icon: habitEditData.icon,
end_date: habitEditData?.endDate?.toISOString(),
}) })
.eq("id", habitEditData.id) .eq("id", habitEditData.id)
.select("*") .select("*")
@ -43,6 +44,10 @@ export class HabitEditSupabaseRepository
}), }),
color: updatedHabit.color, color: updatedHabit.color,
startDate: new Date(updatedHabit.start_date), startDate: new Date(updatedHabit.start_date),
endDate:
updatedHabit.end_date != null
? new Date(updatedHabit.end_date)
: undefined,
}) })
return habit return habit
} }

View File

@ -7,10 +7,15 @@ import type {
RetrieveHabitsTrackerUseCase, RetrieveHabitsTrackerUseCase,
RetrieveHabitsTrackerUseCaseOptions, RetrieveHabitsTrackerUseCaseOptions,
} from "@/domain/use-cases/RetrieveHabitsTracker" } from "@/domain/use-cases/RetrieveHabitsTracker"
import type { HabitCreateData, HabitEditData } from "@/domain/entities/Habit" import type {
Habit,
HabitCreateData,
HabitEditData,
} from "@/domain/entities/Habit"
import { getErrorsFieldsFromZodError } from "../../utils/zod" import { getErrorsFieldsFromZodError } from "../../utils/zod"
import type { HabitCreateUseCase } from "@/domain/use-cases/HabitCreate" import type { HabitCreateUseCase } from "@/domain/use-cases/HabitCreate"
import type { HabitEditUseCase } from "@/domain/use-cases/HabitEdit" import type { HabitEditUseCase } from "@/domain/use-cases/HabitEdit"
import type { HabitStopUseCase } from "@/domain/use-cases/HabitStop"
import type { import type {
HabitGoalProgressUpdateUseCase, HabitGoalProgressUpdateUseCase,
HabitGoalProgressUpdateUseCaseOptions, HabitGoalProgressUpdateUseCaseOptions,
@ -39,6 +44,10 @@ export interface HabitsTrackerPresenterState {
} }
} }
habitStop: {
state: FetchState
}
habitGoalProgressUpdate: { habitGoalProgressUpdate: {
state: FetchState state: FetchState
} }
@ -48,6 +57,7 @@ export interface HabitsTrackerPresenterOptions {
retrieveHabitsTrackerUseCase: RetrieveHabitsTrackerUseCase retrieveHabitsTrackerUseCase: RetrieveHabitsTrackerUseCase
habitCreateUseCase: HabitCreateUseCase habitCreateUseCase: HabitCreateUseCase
habitEditUseCase: HabitEditUseCase habitEditUseCase: HabitEditUseCase
habitStopUseCase: HabitStopUseCase
habitGoalProgressUpdateUseCase: HabitGoalProgressUpdateUseCase habitGoalProgressUpdateUseCase: HabitGoalProgressUpdateUseCase
} }
@ -58,6 +68,7 @@ export class HabitsTrackerPresenter
public retrieveHabitsTrackerUseCase: RetrieveHabitsTrackerUseCase public retrieveHabitsTrackerUseCase: RetrieveHabitsTrackerUseCase
public habitCreateUseCase: HabitCreateUseCase public habitCreateUseCase: HabitCreateUseCase
public habitEditUseCase: HabitEditUseCase public habitEditUseCase: HabitEditUseCase
public habitStopUseCase: HabitStopUseCase
public habitGoalProgressUpdateUseCase: HabitGoalProgressUpdateUseCase public habitGoalProgressUpdateUseCase: HabitGoalProgressUpdateUseCase
public constructor(options: HabitsTrackerPresenterOptions) { public constructor(options: HabitsTrackerPresenterOptions) {
@ -65,6 +76,7 @@ export class HabitsTrackerPresenter
retrieveHabitsTrackerUseCase, retrieveHabitsTrackerUseCase,
habitCreateUseCase, habitCreateUseCase,
habitEditUseCase, habitEditUseCase,
habitStopUseCase,
habitGoalProgressUpdateUseCase, habitGoalProgressUpdateUseCase,
} = options } = options
const habitsTracker = HabitsTracker.default() const habitsTracker = HabitsTracker.default()
@ -85,6 +97,9 @@ export class HabitsTrackerPresenter
global: null, global: null,
}, },
}, },
habitStop: {
state: "idle",
},
habitGoalProgressUpdate: { habitGoalProgressUpdate: {
state: "idle", state: "idle",
}, },
@ -92,6 +107,7 @@ export class HabitsTrackerPresenter
this.retrieveHabitsTrackerUseCase = retrieveHabitsTrackerUseCase this.retrieveHabitsTrackerUseCase = retrieveHabitsTrackerUseCase
this.habitCreateUseCase = habitCreateUseCase this.habitCreateUseCase = habitCreateUseCase
this.habitEditUseCase = habitEditUseCase this.habitEditUseCase = habitEditUseCase
this.habitStopUseCase = habitStopUseCase
this.habitGoalProgressUpdateUseCase = habitGoalProgressUpdateUseCase this.habitGoalProgressUpdateUseCase = habitGoalProgressUpdateUseCase
} }
@ -153,6 +169,25 @@ export class HabitsTrackerPresenter
} }
} }
public async habitStop(habitToStop: Habit): Promise<FetchState> {
try {
this.setState((state) => {
state.habitStop.state = "loading"
})
const habit = await this.habitStopUseCase.execute(habitToStop)
this.setState((state) => {
state.habitStop.state = "success"
state.habitsTracker.editHabit(habit)
})
return "success"
} catch (error) {
this.setState((state) => {
state.habitStop.state = "error"
})
return "error"
}
}
public async retrieveHabitsTracker( public async retrieveHabitsTracker(
options: RetrieveHabitsTrackerUseCaseOptions, options: RetrieveHabitsTrackerUseCaseOptions,
): Promise<void> { ): Promise<void> {

View File

@ -19,7 +19,7 @@ export interface HabitEditFormProps {
} }
export const HabitEditForm: React.FC<HabitEditFormProps> = ({ habit }) => { export const HabitEditForm: React.FC<HabitEditFormProps> = ({ habit }) => {
const { habitEdit, habitsTrackerPresenter } = useHabitsTracker() const { habitEdit, habitStop, habitsTrackerPresenter } = useHabitsTracker()
const { const {
control, control,
@ -134,6 +134,18 @@ export const HabitEditForm: React.FC<HabitEditFormProps> = ({ habit }) => {
> >
Save Save
</Button> </Button>
<Button
mode="outlined"
onPress={async () => {
await habitsTrackerPresenter.habitStop(habit)
}}
loading={habitStop.state === "loading"}
disabled={habitStop.state === "loading"}
style={[styles.spacing, { width: "90%" }]}
>
Stop
</Button>
</ScrollView> </ScrollView>
<Snackbar <Snackbar

View File

@ -90,16 +90,24 @@ export const HabitsList: React.FC<HabitsListProps> = (props) => {
}, },
]} ]}
> >
{habitsTracker.habitsHistory[frequency].map((item) => { {habitsTracker.habitsHistory[frequency]
return ( .filter((habitItem) => {
<HabitCard return (
habitHistory={item} (habitItem.habit.endDate != null &&
selectedDate={selectedDate} habitItem.habit.endDate <= selectedDate) ||
key={item.habit.id + selectedDate.toISOString()} habitItem.habit.endDate == null
confettiRef={confettiRef} )
/> })
) .map((item) => {
})} return (
<HabitCard
habitHistory={item}
selectedDate={selectedDate}
key={item.habit.id + selectedDate.toISOString()}
confettiRef={confettiRef}
/>
)
})}
</List.Accordion> </List.Accordion>
) )
})} })}