import { ZodError } from "zod" import { HabitsTracker } from "@/domain/entities/HabitsTracker" import type { ErrorGlobal, FetchState } from "./_Presenter" import { Presenter } from "./_Presenter" import type { RetrieveHabitsTrackerUseCase, RetrieveHabitsTrackerUseCaseOptions, } from "@/domain/use-cases/RetrieveHabitsTracker" import type { Habit, HabitCreateData, HabitEditData, } from "@/domain/entities/Habit" import { getErrorsFieldsFromZodError } from "../../utils/zod" import type { HabitCreateUseCase } from "@/domain/use-cases/HabitCreate" import type { HabitEditUseCase } from "@/domain/use-cases/HabitEdit" import type { HabitStopUseCase } from "@/domain/use-cases/HabitStop" import type { HabitGoalProgressUpdateUseCase, HabitGoalProgressUpdateUseCaseOptions, } from "@/domain/use-cases/HabitGoalProgressUpdate" export interface HabitsTrackerPresenterState { habitsTracker: HabitsTracker retrieveHabitsTracker: { state: FetchState } habitCreate: { state: FetchState errors: { fields: Array global: ErrorGlobal } } habitEdit: { state: FetchState errors: { fields: Array global: ErrorGlobal } } habitStop: { state: FetchState } habitGoalProgressUpdate: { state: FetchState } } export interface HabitsTrackerPresenterOptions { retrieveHabitsTrackerUseCase: RetrieveHabitsTrackerUseCase habitCreateUseCase: HabitCreateUseCase habitEditUseCase: HabitEditUseCase habitStopUseCase: HabitStopUseCase habitGoalProgressUpdateUseCase: HabitGoalProgressUpdateUseCase } export class HabitsTrackerPresenter extends Presenter implements HabitsTrackerPresenterOptions { public retrieveHabitsTrackerUseCase: RetrieveHabitsTrackerUseCase public habitCreateUseCase: HabitCreateUseCase public habitEditUseCase: HabitEditUseCase public habitStopUseCase: HabitStopUseCase public habitGoalProgressUpdateUseCase: HabitGoalProgressUpdateUseCase public constructor(options: HabitsTrackerPresenterOptions) { const { retrieveHabitsTrackerUseCase, habitCreateUseCase, habitEditUseCase, habitStopUseCase, habitGoalProgressUpdateUseCase, } = options const habitsTracker = HabitsTracker.default() super({ habitsTracker, retrieveHabitsTracker: { state: "idle" }, habitCreate: { state: "idle", errors: { fields: [], global: null, }, }, habitEdit: { state: "idle", errors: { fields: [], global: null, }, }, habitStop: { state: "idle", }, habitGoalProgressUpdate: { state: "idle", }, }) this.retrieveHabitsTrackerUseCase = retrieveHabitsTrackerUseCase this.habitCreateUseCase = habitCreateUseCase this.habitEditUseCase = habitEditUseCase this.habitStopUseCase = habitStopUseCase this.habitGoalProgressUpdateUseCase = habitGoalProgressUpdateUseCase } public async habitCreate(data: unknown): Promise { try { this.setState((state) => { state.habitCreate.state = "loading" state.habitCreate.errors = { fields: [], global: null, } }) const habit = await this.habitCreateUseCase.execute(data) this.setState((state) => { state.habitCreate.state = "success" state.habitsTracker.addHabit(habit) }) return "success" } catch (error) { this.setState((state) => { state.habitCreate.state = "error" if (error instanceof ZodError) { state.habitCreate.errors.fields = getErrorsFieldsFromZodError(error) } else { state.habitCreate.errors.global = "unknown" } }) return "error" } } public async habitEdit(data: unknown): Promise { try { this.setState((state) => { state.habitEdit.state = "loading" state.habitEdit.errors = { fields: [], global: null, } }) const habit = await this.habitEditUseCase.execute(data) this.setState((state) => { state.habitEdit.state = "success" state.habitsTracker.editHabit(habit) }) return "success" } catch (error) { this.setState((state) => { state.habitEdit.state = "error" if (error instanceof ZodError) { state.habitEdit.errors.fields = getErrorsFieldsFromZodError(error) } else { state.habitEdit.errors.global = "unknown" } }) return "error" } } public async habitStop(habitToStop: Habit): Promise { 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( options: RetrieveHabitsTrackerUseCaseOptions, ): Promise { this.setState((state) => { state.retrieveHabitsTracker.state = "loading" state.habitsTracker = HabitsTracker.default() }) try { const habitsTracker = await this.retrieveHabitsTrackerUseCase.execute(options) this.setState((state) => { state.habitsTracker = habitsTracker state.retrieveHabitsTracker.state = "success" }) } catch (error) { this.setState((state) => { state.retrieveHabitsTracker.state = "error" }) } } public async habitUpdateProgress( options: HabitGoalProgressUpdateUseCaseOptions, ): Promise { try { this.setState((state) => { state.habitGoalProgressUpdate.state = "loading" }) const habitProgress = await this.habitGoalProgressUpdateUseCase.execute(options) this.setState((state) => { state.habitsTracker.updateHabitProgress(habitProgress) state.habitGoalProgressUpdate.state = "success" }) return "success" } catch (error) { this.setState((state) => { state.habitGoalProgressUpdate.state = "error" }) return "error" } } }