feat: add react-hook-form + zod
This commit is contained in:
parent
bfaada5b4f
commit
90c8c7547f
22
README.md
22
README.md
@ -22,9 +22,10 @@ Un tracker d'habitudes pour performer au boulot et dans la vie de tous les jours
|
|||||||
|
|
||||||
#### Principaux Outils Informatiques Utilisés
|
#### Principaux Outils Informatiques Utilisés
|
||||||
|
|
||||||
- [React Native](https://reactnative.dev/) + [Expo](https://expo.io/): Framework pour le développement d'applications mobiles.
|
|
||||||
- [TypeScript](https://www.typescriptlang.org/): Langage de programmation.
|
- [TypeScript](https://www.typescriptlang.org/): Langage de programmation.
|
||||||
|
- [React Native](https://reactnative.dev/) + [Expo](https://expo.io/): Framework pour le développement d'applications mobiles.
|
||||||
- [React Native Paper](https://callstack.github.io/react-native-paper/): Bibliothèque de composants pour React Native.
|
- [React Native Paper](https://callstack.github.io/react-native-paper/): Bibliothèque de composants pour React Native.
|
||||||
|
- [React Hook Form](https://react-hook-form.com/) + [Zod](https://zod.dev/): Gestion des formulaires et validation des données.
|
||||||
- [Supabase](https://supabase.io/): Backend, serveur d'API pour le stockage des données.
|
- [Supabase](https://supabase.io/): Backend, serveur d'API pour le stockage des données.
|
||||||
<!--
|
<!--
|
||||||
- [WatermelonDB](https://nozbe.github.io/WatermelonDB/): Base de données locale, pour permettre une utilisation hors-ligne de l'application.
|
- [WatermelonDB](https://nozbe.github.io/WatermelonDB/): Base de données locale, pour permettre une utilisation hors-ligne de l'application.
|
||||||
@ -68,3 +69,22 @@ Ce n'est pas strictement nécessaire pour le développement de l'application (m
|
|||||||
```sh
|
```sh
|
||||||
npm run supabase
|
npm run supabase
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Principales Commandes Supabase
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Pour réinitialiser la base de données avec les données de test (seed.sql)
|
||||||
|
npm run supabase db reset
|
||||||
|
|
||||||
|
# Pour synchroniser la base de données (remote) avec le modèle (local)
|
||||||
|
npm run supabase db pull
|
||||||
|
|
||||||
|
# Pour synchroniser le modèle (local) avec la base de données (remote)
|
||||||
|
npm run supabase db push
|
||||||
|
|
||||||
|
# Pour générer les types TypeScript
|
||||||
|
npm run supabase gen types typescript -- --local > ./infrastructure/repositories/supabase/supabase-types.ts
|
||||||
|
|
||||||
|
# Crée un nouveau script de migration à partir des modifications déjà appliquées à votre base de données locale (remplacer `<name-of-migration>` avec le nom de la migration)
|
||||||
|
npm run supabase db diff -- -f <name-of-migration>
|
||||||
|
```
|
||||||
|
@ -16,7 +16,7 @@ npm run lint:typescript
|
|||||||
npm run test
|
npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
Une pipeline CI ([`.gitlab-ci.yml`](.gitlab-ci.yml)) est en place pour vérifier que le code respecte ces bonnes pratiques et que les tests passent.
|
Une pipeline CI ([`.gitlab-ci.yml`](../.gitlab-ci.yml)) est en place pour vérifier que le code respecte ces bonnes pratiques et que les tests passent.
|
||||||
|
|
||||||
## GitFlow
|
## GitFlow
|
||||||
|
|
||||||
|
@ -7,6 +7,10 @@ export type GoalType = (typeof GOAL_TYPES)[number]
|
|||||||
interface GoalBase {
|
interface GoalBase {
|
||||||
frequency: GoalFrequency
|
frequency: GoalFrequency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GoalBaseJSON extends GoalBase {
|
||||||
|
type: GoalType
|
||||||
|
}
|
||||||
export abstract class Goal implements GoalBase {
|
export abstract class Goal implements GoalBase {
|
||||||
public frequency: GoalBase["frequency"]
|
public frequency: GoalBase["frequency"]
|
||||||
public abstract readonly type: GoalType
|
public abstract readonly type: GoalType
|
||||||
@ -29,14 +33,18 @@ export abstract class Goal implements GoalBase {
|
|||||||
public isBoolean(): this is GoalBoolean {
|
public isBoolean(): this is GoalBoolean {
|
||||||
return Goal.isBoolean(this)
|
return Goal.isBoolean(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract toJSON(): GoalBaseJSON
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GoalProgressBase {
|
export interface GoalProgressBase {
|
||||||
goal: Goal
|
goal: Goal
|
||||||
}
|
}
|
||||||
export abstract class GoalProgress implements GoalProgressBase {
|
export abstract class GoalProgress implements GoalProgressBase {
|
||||||
public abstract readonly goal: Goal
|
public abstract readonly goal: Goal
|
||||||
public abstract isCompleted(): boolean
|
public abstract isCompleted(): boolean
|
||||||
|
|
||||||
|
public abstract toJSON(): GoalProgressBase
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GoalNumericOptions extends GoalBase {
|
interface GoalNumericOptions extends GoalBase {
|
||||||
@ -57,6 +65,14 @@ export class GoalNumeric extends Goal {
|
|||||||
const { target } = options
|
const { target } = options
|
||||||
this.target = target
|
this.target = target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override toJSON(): GoalNumericOptions & GoalBaseJSON {
|
||||||
|
return {
|
||||||
|
frequency: this.frequency,
|
||||||
|
target: this.target,
|
||||||
|
type: this.type,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
interface GoalNumericProgressOptions extends GoalProgressBase {
|
interface GoalNumericProgressOptions extends GoalProgressBase {
|
||||||
goal: GoalNumeric
|
goal: GoalNumeric
|
||||||
@ -82,10 +98,24 @@ export class GoalNumericProgress extends GoalProgress {
|
|||||||
? 0
|
? 0
|
||||||
: this.progress / this.goal.target.value
|
: this.progress / this.goal.target.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override toJSON(): GoalNumericProgressOptions {
|
||||||
|
return {
|
||||||
|
goal: this.goal,
|
||||||
|
progress: this.progress,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GoalBoolean extends Goal {
|
export class GoalBoolean extends Goal {
|
||||||
public readonly type = "boolean"
|
public readonly type = "boolean"
|
||||||
|
|
||||||
|
public override toJSON(): GoalBaseJSON {
|
||||||
|
return {
|
||||||
|
frequency: this.frequency,
|
||||||
|
type: this.type,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
interface GoalBooleanProgressOptions extends GoalProgressBase {
|
interface GoalBooleanProgressOptions extends GoalProgressBase {
|
||||||
goal: GoalBoolean
|
goal: GoalBoolean
|
||||||
@ -105,4 +135,11 @@ export class GoalBooleanProgress extends GoalProgress {
|
|||||||
public override isCompleted(): boolean {
|
public override isCompleted(): boolean {
|
||||||
return this.progress
|
return this.progress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override toJSON(): GoalBooleanProgressOptions {
|
||||||
|
return {
|
||||||
|
goal: this.goal,
|
||||||
|
progress: this.progress,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,42 @@
|
|||||||
import type { Goal } from "./Goal"
|
import { z } from "zod"
|
||||||
import type { User } from "./User"
|
|
||||||
import type { EntityOptions } from "./_Entity"
|
|
||||||
import { Entity } from "./_Entity"
|
|
||||||
|
|
||||||
export interface HabitOptions extends EntityOptions {
|
import type { Goal, GoalBaseJSON } from "./Goal"
|
||||||
userId: User["id"]
|
import { Entity, EntitySchema } from "./_Entity"
|
||||||
name: string
|
|
||||||
color: string
|
export const HabitSchema = EntitySchema.extend({
|
||||||
icon: string
|
userId: z.string(),
|
||||||
|
name: z.string().min(1).max(50),
|
||||||
|
color: z.string().min(4).max(9).regex(/^#/),
|
||||||
|
icon: z.string().min(1),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const HabitCreateSchema = HabitSchema.extend({}).omit({ id: true })
|
||||||
|
export type HabitCreateData = z.infer<typeof HabitCreateSchema>
|
||||||
|
|
||||||
|
type HabitDataBase = z.infer<typeof HabitSchema>
|
||||||
|
|
||||||
|
export interface HabitData extends HabitDataBase {
|
||||||
goal: Goal
|
goal: Goal
|
||||||
startDate: Date
|
startDate: Date
|
||||||
endDate?: Date
|
endDate?: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Habit extends Entity implements HabitOptions {
|
export interface HabitJSON extends HabitDataBase {
|
||||||
public userId: HabitOptions["userId"]
|
goal: GoalBaseJSON
|
||||||
public name: HabitOptions["name"]
|
startDate: string
|
||||||
public color: HabitOptions["color"]
|
endDate?: string
|
||||||
public icon: HabitOptions["icon"]
|
}
|
||||||
public goal: HabitOptions["goal"]
|
|
||||||
public startDate: HabitOptions["startDate"]
|
|
||||||
public endDate?: HabitOptions["endDate"]
|
|
||||||
|
|
||||||
public constructor(options: HabitOptions) {
|
export class Habit extends Entity implements HabitData {
|
||||||
|
public userId: HabitData["userId"]
|
||||||
|
public name: HabitData["name"]
|
||||||
|
public color: HabitData["color"]
|
||||||
|
public icon: HabitData["icon"]
|
||||||
|
public goal: HabitData["goal"]
|
||||||
|
public startDate: HabitData["startDate"]
|
||||||
|
public endDate?: HabitData["endDate"]
|
||||||
|
|
||||||
|
public constructor(options: HabitData) {
|
||||||
const { id, userId, name, color, icon, goal, startDate, endDate } = options
|
const { id, userId, name, color, icon, goal, startDate, endDate } = options
|
||||||
super({ id })
|
super({ id })
|
||||||
this.userId = userId
|
this.userId = userId
|
||||||
@ -33,4 +47,17 @@ export class Habit extends Entity implements HabitOptions {
|
|||||||
this.startDate = startDate
|
this.startDate = startDate
|
||||||
this.endDate = endDate
|
this.endDate = endDate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override toJSON(): HabitJSON {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
userId: this.userId,
|
||||||
|
name: this.name,
|
||||||
|
color: this.color,
|
||||||
|
icon: this.icon,
|
||||||
|
goal: this.goal,
|
||||||
|
startDate: this.startDate.toISOString(),
|
||||||
|
endDate: this.endDate?.toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import type { Habit } from "./Habit"
|
import type { Habit } from "./Habit"
|
||||||
import type { HabitProgress } from "./HabitProgress"
|
import type { HabitProgress } from "./HabitProgress"
|
||||||
|
|
||||||
export interface HabitHistoryOptions {
|
export interface HabitHistoryJSON {
|
||||||
habit: Habit
|
habit: Habit
|
||||||
progressHistory: HabitProgress[]
|
progressHistory: HabitProgress[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HabitHistory implements HabitHistoryOptions {
|
export class HabitHistory implements HabitHistoryJSON {
|
||||||
public habit: Habit
|
public habit: Habit
|
||||||
public progressHistory: HabitProgress[]
|
public progressHistory: HabitProgress[]
|
||||||
|
|
||||||
public constructor(options: HabitHistoryOptions) {
|
public constructor(options: HabitHistoryJSON) {
|
||||||
const { habit, progressHistory } = options
|
const { habit, progressHistory } = options
|
||||||
this.habit = habit
|
this.habit = habit
|
||||||
this.progressHistory = progressHistory
|
this.progressHistory = progressHistory
|
||||||
|
@ -1,24 +1,41 @@
|
|||||||
import type { GoalProgress } from "./Goal"
|
import type { GoalProgress, GoalProgressBase } from "./Goal"
|
||||||
import type { Habit } from "./Habit"
|
import type { Habit } from "./Habit"
|
||||||
import type { EntityOptions } from "./_Entity"
|
import type { EntityData } from "./_Entity"
|
||||||
import { Entity } from "./_Entity"
|
import { Entity } from "./_Entity"
|
||||||
|
|
||||||
export interface HabitProgressOptions extends EntityOptions {
|
interface HabitProgressDataBase extends EntityData {
|
||||||
habitId: Habit["id"]
|
habitId: Habit["id"]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HabitProgressData extends HabitProgressDataBase {
|
||||||
goalProgress: GoalProgress
|
goalProgress: GoalProgress
|
||||||
date: Date
|
date: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HabitProgress extends Entity implements HabitProgressOptions {
|
export interface HabitProgressJSON extends HabitProgressDataBase {
|
||||||
public habitId: HabitProgressOptions["habitId"]
|
goalProgress: GoalProgressBase
|
||||||
public goalProgress: HabitProgressOptions["goalProgress"]
|
date: string
|
||||||
public date: HabitProgressOptions["date"]
|
}
|
||||||
|
|
||||||
public constructor(options: HabitProgressOptions) {
|
export class HabitProgress extends Entity implements HabitProgressData {
|
||||||
|
public habitId: HabitProgressData["habitId"]
|
||||||
|
public goalProgress: HabitProgressData["goalProgress"]
|
||||||
|
public date: HabitProgressData["date"]
|
||||||
|
|
||||||
|
public constructor(options: HabitProgressData) {
|
||||||
const { id, habitId, goalProgress, date } = options
|
const { id, habitId, goalProgress, date } = options
|
||||||
super({ id })
|
super({ id })
|
||||||
this.habitId = habitId
|
this.habitId = habitId
|
||||||
this.goalProgress = goalProgress
|
this.goalProgress = goalProgress
|
||||||
this.date = date
|
this.date = date
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override toJSON(): HabitProgressJSON {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
habitId: this.habitId,
|
||||||
|
goalProgress: this.goalProgress,
|
||||||
|
date: this.date.toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import type { HabitHistory } from "./HabitHistory"
|
import type { HabitHistory } from "./HabitHistory"
|
||||||
|
|
||||||
export interface HabitsTrackerOptions {
|
export interface HabitsTrackerData {
|
||||||
habitsHistory: HabitHistory[]
|
habitsHistory: HabitHistory[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HabitsTracker implements HabitsTrackerOptions {
|
export class HabitsTracker implements HabitsTrackerData {
|
||||||
public habitsHistory: HabitHistory[]
|
public habitsHistory: HabitHistory[]
|
||||||
|
|
||||||
public constructor(options: HabitsTrackerOptions) {
|
public constructor(options: HabitsTrackerData) {
|
||||||
const { habitsHistory } = options
|
const { habitsHistory } = options
|
||||||
this.habitsHistory = habitsHistory
|
this.habitsHistory = habitsHistory
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,35 @@
|
|||||||
import type { EntityOptions } from "./_Entity"
|
import { z } from "zod"
|
||||||
import { Entity } from "./_Entity"
|
|
||||||
|
|
||||||
export interface UserOptions extends EntityOptions {
|
import { Entity, EntitySchema } from "./_Entity"
|
||||||
email: string
|
|
||||||
displayName: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class User extends Entity implements UserOptions {
|
export const UserSchema = EntitySchema.extend({
|
||||||
public email: UserOptions["email"]
|
email: z.string().min(1).email(),
|
||||||
public displayName: UserOptions["displayName"]
|
displayName: z.string().min(1),
|
||||||
|
})
|
||||||
|
|
||||||
public constructor(options: UserOptions) {
|
export const UserRegisterSchema = UserSchema.extend({
|
||||||
|
password: z.string().min(2),
|
||||||
|
}).omit({ id: true })
|
||||||
|
export type UserRegisterData = z.infer<typeof UserRegisterSchema>
|
||||||
|
|
||||||
|
export type UserData = z.infer<typeof UserSchema>
|
||||||
|
|
||||||
|
export class User extends Entity implements UserData {
|
||||||
|
public email: UserData["email"]
|
||||||
|
public displayName: UserData["displayName"]
|
||||||
|
|
||||||
|
public constructor(options: UserData) {
|
||||||
const { id, email, displayName } = options
|
const { id, email, displayName } = options
|
||||||
super({ id })
|
super({ id })
|
||||||
this.email = email
|
this.email = email
|
||||||
this.displayName = displayName
|
this.displayName = displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override toJSON(): UserData {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
email: this.email,
|
||||||
|
displayName: this.displayName,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
export interface EntityOptions {
|
import { z } from "zod"
|
||||||
id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class Entity implements EntityOptions {
|
export const EntitySchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type EntityData = z.infer<typeof EntitySchema>
|
||||||
|
|
||||||
|
export abstract class Entity implements EntityData {
|
||||||
public readonly id: string
|
public readonly id: string
|
||||||
|
|
||||||
public constructor(options: EntityOptions) {
|
public constructor(options: EntityData) {
|
||||||
const { id } = options
|
const { id } = options
|
||||||
this.id = id
|
this.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
// public equals(entity: Entity): boolean {
|
public equals(entity: Entity): boolean {
|
||||||
// return entity.id === this.id
|
return entity.id === this.id
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
public abstract toJSON(): EntityData
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,12 @@ export class RetrieveHabitsTrackerUseCase
|
|||||||
await this.getHabitProgressHistoryRepository.execute({
|
await this.getHabitProgressHistoryRepository.execute({
|
||||||
habit,
|
habit,
|
||||||
})
|
})
|
||||||
return new HabitHistory({ habit, progressHistory })
|
return new HabitHistory({
|
||||||
|
habit,
|
||||||
|
progressHistory: progressHistory.sort((a, b) => {
|
||||||
|
return a.date.getTime() - b.date.getTime()
|
||||||
|
}),
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const habitsTracker = new HabitsTracker({
|
const habitsTracker = new HabitsTracker({
|
||||||
|
36
package-lock.json
generated
36
package-lock.json
generated
@ -10,6 +10,7 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "14.0.0",
|
"@expo/vector-icons": "14.0.0",
|
||||||
|
"@hookform/resolvers": "3.3.4",
|
||||||
"@react-navigation/native": "6.1.16",
|
"@react-navigation/native": "6.1.16",
|
||||||
"@supabase/supabase-js": "2.39.8",
|
"@supabase/supabase-js": "2.39.8",
|
||||||
"expo": "50.0.13",
|
"expo": "50.0.13",
|
||||||
@ -23,13 +24,15 @@
|
|||||||
"immer": "10.0.4",
|
"immer": "10.0.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
"react-hook-form": "7.51.1",
|
||||||
"react-native": "0.73.5",
|
"react-native": "0.73.5",
|
||||||
"react-native-calendars": "1.1304.1",
|
"react-native-calendars": "1.1304.1",
|
||||||
"react-native-paper": "5.12.3",
|
"react-native-paper": "5.12.3",
|
||||||
"react-native-safe-area-context": "4.8.2",
|
"react-native-safe-area-context": "4.8.2",
|
||||||
"react-native-screens": "3.29.0",
|
"react-native-screens": "3.29.0",
|
||||||
"react-native-vector-icons": "10.0.3",
|
"react-native-vector-icons": "10.0.3",
|
||||||
"react-native-web": "0.19.10"
|
"react-native-web": "0.19.10",
|
||||||
|
"zod": "3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.24.0",
|
"@babel/core": "7.24.0",
|
||||||
@ -4261,6 +4264,14 @@
|
|||||||
"@hapi/hoek": "^9.0.0"
|
"@hapi/hoek": "^9.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@hookform/resolvers": {
|
||||||
|
"version": "3.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.3.4.tgz",
|
||||||
|
"integrity": "sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-hook-form": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.14",
|
"version": "0.11.14",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||||
@ -19905,6 +19916,21 @@
|
|||||||
"react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0"
|
"react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-hook-form": {
|
||||||
|
"version": "7.51.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.1.tgz",
|
||||||
|
"integrity": "sha512-ifnBjl+kW0ksINHd+8C/Gp6a4eZOdWyvRv0UBaByShwU8JbVx5hTcTWEcd5VdybvmPTATkVVXk9npXArHmo56w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/react-hook-form"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
@ -23183,6 +23209,14 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zod": {
|
||||||
|
"version": "3.22.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
|
||||||
|
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
"lint:typescript": "tsc --noEmit",
|
"lint:typescript": "tsc --noEmit",
|
||||||
"lint:staged": "lint-staged",
|
"lint:staged": "lint-staged",
|
||||||
"test": "jest --coverage --reporters=default --reporters=jest-junit",
|
"test": "jest --coverage --reporters=default --reporters=jest-junit",
|
||||||
"supabase": "supabase --workdir \"./data/infrastructure/repositories\"",
|
"supabase": "supabase --workdir \"./infrastructure/repositories\"",
|
||||||
"postinstall": "husky"
|
"postinstall": "husky"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "14.0.0",
|
"@expo/vector-icons": "14.0.0",
|
||||||
|
"@hookform/resolvers": "3.3.4",
|
||||||
"@react-navigation/native": "6.1.16",
|
"@react-navigation/native": "6.1.16",
|
||||||
"@supabase/supabase-js": "2.39.8",
|
"@supabase/supabase-js": "2.39.8",
|
||||||
"expo": "50.0.13",
|
"expo": "50.0.13",
|
||||||
@ -32,13 +33,15 @@
|
|||||||
"immer": "10.0.4",
|
"immer": "10.0.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
"react-hook-form": "7.51.1",
|
||||||
"react-native": "0.73.5",
|
"react-native": "0.73.5",
|
||||||
"react-native-calendars": "1.1304.1",
|
"react-native-calendars": "1.1304.1",
|
||||||
"react-native-paper": "5.12.3",
|
"react-native-paper": "5.12.3",
|
||||||
"react-native-safe-area-context": "4.8.2",
|
"react-native-safe-area-context": "4.8.2",
|
||||||
"react-native-screens": "3.29.0",
|
"react-native-screens": "3.29.0",
|
||||||
"react-native-vector-icons": "10.0.3",
|
"react-native-vector-icons": "10.0.3",
|
||||||
"react-native-web": "0.19.10"
|
"react-native-web": "0.19.10",
|
||||||
|
"zod": "3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.24.0",
|
"@babel/core": "7.24.0",
|
||||||
|
Reference in New Issue
Block a user