2024-04-04 17:06:42 +02:00
import { zodResolver } from "@hookform/resolvers/zod"
import { Controller , useForm } from "react-hook-form"
2024-04-05 00:08:40 +02:00
import { ScrollView , StyleSheet } from "react-native"
2024-04-04 17:26:48 +02:00
import {
Button ,
HelperText ,
2024-04-11 15:26:20 +02:00
IconButton ,
2024-04-04 17:26:48 +02:00
SegmentedButtons ,
2024-04-05 00:08:40 +02:00
Snackbar ,
2024-04-04 17:33:51 +02:00
Text ,
2024-04-04 17:26:48 +02:00
TextInput ,
2024-04-11 15:26:20 +02:00
Tooltip ,
2024-04-04 17:26:48 +02:00
} from "react-native-paper"
2024-04-04 12:31:56 +02:00
import { SafeAreaView } from "react-native-safe-area-context"
2024-04-04 17:06:42 +02:00
import ColorPicker , {
HueSlider ,
Panel1 ,
Preview ,
} from "reanimated-color-picker"
2024-04-05 00:08:40 +02:00
import { useState } from "react"
2024-04-04 12:31:56 +02:00
2024-04-04 17:33:51 +02:00
import type { GoalFrequency , GoalType } from "@/domain/entities/Goal"
import { GOAL_FREQUENCIES , GOAL_TYPES } from "@/domain/entities/Goal"
2024-04-04 12:31:56 +02:00
import type { HabitCreateData } from "@/domain/entities/Habit"
2024-04-04 17:06:42 +02:00
import { HabitCreateSchema } from "@/domain/entities/Habit"
2024-04-04 12:31:56 +02:00
import type { User } from "@/domain/entities/User"
2024-04-05 00:08:40 +02:00
import { useHabitsTracker } from "../../contexts/HabitsTracker"
2024-04-11 15:26:20 +02:00
import { HabitIconSelectorModal } from "./HabitIconSelectorModal"
2024-04-04 12:31:56 +02:00
export interface HabitCreateFormProps {
user : User
}
export const HabitCreateForm : React.FC < HabitCreateFormProps > = ( { user } ) = > {
2024-04-05 00:08:40 +02:00
const { habitCreate , habitsTrackerPresenter } = useHabitsTracker ( )
2024-04-04 17:26:48 +02:00
2024-04-04 17:06:42 +02:00
const {
control ,
handleSubmit ,
2024-04-05 00:08:40 +02:00
reset ,
2024-04-04 17:06:42 +02:00
formState : { errors } ,
} = useForm < HabitCreateData > ( {
mode : "onChange" ,
resolver : zodResolver ( HabitCreateSchema ) ,
2024-04-04 12:31:56 +02:00
defaultValues : {
userId : user.id ,
name : "" ,
color : "#006CFF" ,
2024-04-11 15:26:20 +02:00
icon : "circle-question" ,
2024-04-04 12:31:56 +02:00
goal : {
frequency : "daily" ,
target : {
type : "boolean" ,
} ,
} ,
} ,
} )
2024-04-05 00:08:40 +02:00
const [ isVisibleSnackbar , setIsVisibleSnackbar ] = useState ( false )
const onDismissSnackbar = ( ) : void = > {
setIsVisibleSnackbar ( false )
}
const onSubmit = async ( data : HabitCreateData ) : Promise < void > = > {
await habitsTrackerPresenter . habitCreate ( data )
setIsVisibleSnackbar ( true )
reset ( )
}
const habitFrequenciesTranslations : {
[ key in GoalFrequency ] : { label : string ; icon : string }
} = {
daily : {
label : "Daily" ,
icon : "calendar" ,
} ,
weekly : {
label : "Weekly" ,
icon : "calendar-week" ,
} ,
monthly : {
label : "Monthly" ,
icon : "calendar-month" ,
} ,
}
const habitTypesTranslations : {
[ key in GoalType ] : { label : string ; icon : string }
} = {
boolean : {
label : "Routine" ,
icon : "clock" ,
} ,
numeric : {
label : "Target" ,
icon : "target" ,
} ,
}
2024-04-04 12:31:56 +02:00
return (
< SafeAreaView >
2024-04-05 00:08:40 +02:00
< ScrollView
contentContainerStyle = { {
justifyContent : "center" ,
alignItems : "center" ,
paddingHorizontal : 20 ,
} }
>
< Controller
control = { control }
render = { ( { field : { onChange , onBlur , value } } ) = > {
return (
< >
< TextInput
placeholder = "Name"
onBlur = { onBlur }
onChangeText = { onChange }
value = { value }
style = { [
styles . spacing ,
{
width : "90%" ,
} ,
] }
mode = "outlined"
/ >
{ errors . name != null ? (
< HelperText type = "error" visible style = { [ { paddingTop : 0 } ] } >
{ errors . name . type === "too_big"
? "Name is too long"
: "Name is required" }
< / HelperText >
) : null }
< / >
)
} }
name = "name"
/ >
< Controller
control = { control }
render = { ( { field : { onChange , value } } ) = > {
return (
< >
< Text style = { [ styles . spacing ] } > Habit Frequency < / Text >
< SegmentedButtons
style = { [ { width : "90%" } ] }
onValueChange = { onChange }
value = { value }
buttons = { GOAL_FREQUENCIES . map ( ( frequency ) = > {
return {
label : habitFrequenciesTranslations [ frequency ] . label ,
value : frequency ,
icon : habitFrequenciesTranslations [ frequency ] . icon ,
}
} ) }
/ >
< / >
)
2024-04-04 12:31:56 +02:00
} }
2024-04-05 00:08:40 +02:00
name = "goal.frequency"
2024-04-04 12:31:56 +02:00
/ >
2024-04-04 17:06:42 +02:00
2024-04-05 00:08:40 +02:00
< Controller
control = { control }
render = { ( { field : { onChange , value } } ) = > {
return (
< >
2024-04-11 15:26:20 +02:00
< Text
style = { [
styles . spacing ,
{ justifyContent : "center" , alignContent : "center" } ,
] }
>
Habit Type
< Tooltip
title = "Routine habits are activities performed regularly, while Target habits involve setting specific objectives to be achieved through repeated actions."
enterTouchDelay = { 50 }
leaveTouchDelay = { 25 }
>
< IconButton
icon = "chat-question-outline"
selected
size = { 24 }
onPress = { ( ) = > { } }
style = { { alignSelf : "center" } }
/ >
< / Tooltip >
< / Text >
2024-04-05 00:08:40 +02:00
< SegmentedButtons
style = { [ { width : "90%" } ] }
onValueChange = { onChange }
value = { value }
buttons = { GOAL_TYPES . map ( ( type ) = > {
return {
label : habitTypesTranslations [ type ] . label ,
value : type ,
icon : habitTypesTranslations [ type ] . icon ,
}
} ) }
/ >
< / >
)
} }
name = "goal.target.type"
/ >
< Controller
control = { control }
render = { ( { field : { onChange , value } } ) = > {
return (
< ColorPicker
style = { [ styles . spacing , { width : "90%" } ] }
value = { value }
onComplete = { ( value ) = > {
onChange ( value . hex )
} }
>
< Preview hideInitialColor / >
< Panel1 / >
< HueSlider / >
< / ColorPicker >
)
} }
name = "color"
/ >
< Controller
control = { control }
2024-04-12 10:29:23 +02:00
render = { ( { field : { onChange , value } } ) = > {
2024-04-05 00:08:40 +02:00
return (
2024-04-11 15:26:20 +02:00
< HabitIconSelectorModal
visible
2024-04-04 17:06:42 +02:00
value = { value }
2024-04-11 15:26:20 +02:00
onDismiss = { ( ) = > { } }
onSelect = { onChange }
onPress = { ( ) = > { } }
2024-04-04 17:06:42 +02:00
/ >
2024-04-05 00:08:40 +02:00
)
} }
name = "icon"
/ >
< Button
mode = "contained"
onPress = { handleSubmit ( onSubmit ) }
loading = { habitCreate . state === "loading" }
disabled = { habitCreate . state === "loading" }
style = { [ styles . spacing , { width : "90%" } ] }
>
Create your habit ! 🚀
< / Button >
< / ScrollView >
< Snackbar
visible = { isVisibleSnackbar }
onDismiss = { onDismissSnackbar }
duration = { 2 _000 }
2024-04-04 17:06:42 +02:00
>
2024-04-05 00:08:40 +02:00
✅ Habit created successfully !
< / Snackbar >
2024-04-04 12:31:56 +02:00
< / SafeAreaView >
)
}
2024-04-04 17:06:42 +02:00
2024-04-05 00:08:40 +02:00
const styles = StyleSheet . create ( {
spacing : {
marginVertical : 16 ,
2024-04-04 17:06:42 +02:00
} ,
2024-04-05 00:08:40 +02:00
} )