Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b927830
initial commit
NNakreSS Jul 27, 2024
c879c63
added phoneInput
NNakreSS Aug 1, 2024
68bb565
initial commit
NNakreSS Aug 1, 2024
836b6e8
added form components
NNakreSS Aug 1, 2024
4c1c203
added emergency components
NNakreSS Aug 1, 2024
14be79e
initial commit
NNakreSS Aug 1, 2024
2ae4891
added react-form , react-phone-input-2 , zod
NNakreSS Aug 1, 2024
5f273a4
initial commit
NNakreSS Aug 1, 2024
e6c92bd
phone input configured as component
NNakreSS Aug 1, 2024
25f9d5a
initial commit
NNakreSS Aug 1, 2024
4d4ed30
added select
NNakreSS Aug 1, 2024
ca72e06
added select
NNakreSS Aug 1, 2024
acd4e28
initial commit
NNakreSS Aug 1, 2024
563ac4d
added SelectLocation
NNakreSS Aug 1, 2024
0624920
refactor name
NNakreSS Aug 1, 2024
bb9c6d6
added new shadcn components
NNakreSS Aug 1, 2024
0540943
tree shake
NNakreSS Aug 1, 2024
4b5262f
fixed turkish char
NNakreSS Aug 2, 2024
6c061b2
fix changed city
NNakreSS Aug 2, 2024
2194174
removed form controller prop
NNakreSS Aug 2, 2024
18f3db6
added dependency for useEffect
NNakreSS Aug 2, 2024
d7225c6
added blue
NNakreSS Aug 2, 2024
f206689
added initial form values , adress field , seatingCount label
NNakreSS Aug 2, 2024
319e318
added loading state , defaultValues for form , submit form , phoneVal…
NNakreSS Aug 2, 2024
31bc161
created form
NNakreSS Aug 2, 2024
a9edab6
added min length validates
NNakreSS Aug 2, 2024
cc36dfd
initial commit
NNakreSS Aug 2, 2024
2945456
fixed turkish char error
NNakreSS Aug 2, 2024
1dfa402
finally set step 1
NNakreSS Aug 2, 2024
8b6d461
added error handlers
NNakreSS Aug 2, 2024
a8e2d13
feature: switching the county selection box to disabled when the city…
NNakreSS Aug 6, 2024
36ae53e
fix: fixed variable name error
NNakreSS Aug 6, 2024
eb5c94a
fix: autocomplete disabled for phone number
NNakreSS Aug 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,268 changes: 962 additions & 306 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@
"lint": "next lint"
},
"dependencies": {
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toast": "^1.2.1",
"@reduxjs/toolkit": "^2.2.3",
"axios": "^1.6.8",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"embla-carousel-autoplay": "^8.1.6",
"embla-carousel-react": "^8.1.6",
"i18next": "^23.11.3",
Expand All @@ -26,13 +32,16 @@
"next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.52.1",
"react-i18next": "^14.1.1",
"react-icons": "^5.2.1",
"react-phone-input-2": "^2.15.1",
"react-redux": "^9.1.1",
"redux-persist": "^6.0.0",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.1"
"vaul": "^0.9.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/node": "^20",
Expand Down
1 change: 1 addition & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
--nightBlue: 219.0 33.0% 16.0%;
--olivieGreen: 74.0 43.0% 51.0% 0.2;
--green: 74.0 43.0% 51.0%;
--submitBlue: 198 100%, 50%
}

.dark {
Expand Down
307 changes: 307 additions & 0 deletions src/components/EmergencyForm/OtherEvacuationForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
'use client'

import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { formSchema, type FormSchema } from '@/components/EmergencyForm/schema/formSchema'
import { Form, FormControl, FormField, FormItem, FormMessage } from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'

import { CountryData } from 'react-phone-input-2'
import 'react-phone-input-2/lib/style.css'
import PhoneInput from '@/components/ui/PhoneInput'
import SelectLocation from '@/components/SelectLocation'
import { Textarea } from '@/components/ui/textarea'
import { Label } from '@/components/ui/label'
import { http } from '@/configs/axiosConfig'
import { toast } from '@/components/ui/toast/use-toast'
import { useState } from 'react'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { FiAlertTriangle } from 'react-icons/fi'

export default function OtherEvacuationForm() {
const [loading, setLoading] = useState<boolean>(false)
const [step, setStep] = useState<number>(1)

const form = useForm<FormSchema>({
resolver: zodResolver(formSchema),
defaultValues: {
applicantFirstName: '',
applicantLastName: '',
applicantPhoneNumber: { countryCode: '90', lineNumber: '' },
firstName: '',
lastName: '',
seatingCount: 0,
phoneNumber: { countryCode: '90', lineNumber: '' },
sourceCity: '',
sourceDistrict: '',
address: '',
targetCity: '',
targetDistrict: ''
}
})

const countryCodeError = form.getFieldState('phoneNumber.countryCode', form.formState).error
const lineNumberError = form.getFieldState('phoneNumber.lineNumber', form.formState).error
const applicantCountryCodeError = form.getFieldState('applicantPhoneNumber.countryCode', form.formState).error
const applicantLineNumberError = form.getFieldState('applicantPhoneNumber.lineNumber', form.formState).error

const nextStep = async () => {
const isValid = await form.trigger(['applicantFirstName', 'applicantLastName', 'applicantPhoneNumber'])
if (isValid) {
setStep(2)
}
}

const prevStep = () => setStep(1)

const handleErrors = (err: any) => {
const errData = err?.response?.data
if (errData && errData.subErrors) {
if (errData.subErrors[0]?.field === 'phoneNumber') {
toast({ variant: 'destructive', title: 'İşlem Başarısız', description: 'Geçerli bir telefon numarası giriniz' })
return
}
}
toast({ variant: 'destructive', title: 'İşlem Başarısız', description: 'İşlem sırasında bir hata meydana geldi' })
}

const onSubmitForm = async (values: FormSchema) => {
setLoading(true)

try {
const { data } = await http.post('emergency-evacuation-application', values)
if (data.isSuccess) {
toast({
variant: 'success',
title: 'İşlem Başarılı',
description: 'Başvurunuz kontrol edilmek üzere başarıyla alınmıştır'
})
setStep(1)
form.reset()
} else {
toast({
variant: 'destructive',
title: 'İşlem Başarısız',
description: 'İşlem sırasında bir hata meydana geldi'
})
}
} catch (err) {
handleErrors(err)
} finally {
setLoading(false)
}
}

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmitForm)} className="text-nightBlue space-y-2">
{
step === 1 ?
<> {/* step 1 */}
<div className="grid grid-cols-2 gap-2">
<FormField key="applicantFirstName" name="applicantFirstName" render={({ field }) => (
<FormItem>
<FormControl>
<Input placeholder="İsim" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)} />

<FormField key="applicantLastName" name="applicantLastName" render={({ field }) => (
<FormItem>
<FormControl>
<Input placeholder="Soyisim" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)} />
</div>

{/*Phone Number block*/}
<FormField key="applicantPhoneNumber" name="applicantPhoneNumber" render={({ field }) => (
<FormItem>
<FormControl>
<PhoneInput
value={field.value.countryCode + field.value.lineNumber}
onChange={(value: string, country: CountryData) => {
const countryCode: string = country.dialCode
const lineNumber: string = value.slice(countryCode.length)
field.onChange({ countryCode, lineNumber })
}}
/>
</FormControl>
{/*<FormMessage />*/}
<div className="text-red-500 font-thin text-sm flex gap-2">
<span>{applicantCountryCodeError?.message}</span>
<span>{applicantLineNumberError?.message}</span>
</div>
</FormItem>
)} />

<div className="grid grid-cols-1 gap-2">
<Alert variant="default" className="bg-transparent border-orange-500 text-backgorund">
<FiAlertTriangle className="text-xl !text-orange-500" />
<AlertTitle className="font-semibold text-orange-500">Dikkat</AlertTitle>
<AlertDescription className="w-full text-orange-500 ">
Formun bu kısmını kendinize ait bilgiler ile doldurarak diğer adıma geçin!
</AlertDescription>
</Alert>
<Button disabled={loading} onClick={nextStep} className="!bg-submitBlue float-end text-lg">
ileri
</Button>
</div>
</> : <> {/* step 2 */}
{/* name surname block*/}
<div className="grid grid-cols-2 gap-2">
<FormField key="firstName" name="firstName" render={({ field }) => (
<FormItem>
<FormControl>
<Input placeholder="İsim" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)} />

<FormField key="lastName" name="lastName" render={({ field }) => (
<FormItem>
<FormControl>
<Input placeholder="Soyisim" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)} />
</div>

{/*Phone Number block*/}
<FormField key="phoneNumber" name="phoneNumber" render={({ field }) => (
<FormItem>
<FormControl>
<PhoneInput
value={field.value.countryCode + field.value.lineNumber}
onChange={(value: string, country: CountryData) => {
const countryCode: string = country.dialCode
const lineNumber: string = value.slice(countryCode.length)
field.onChange({ countryCode, lineNumber })
}}
/>
</FormControl>
{/*<FormMessage />*/}
<div className="text-red-500 font-thin text-sm flex gap-2">
<span>{countryCodeError?.message}</span>
<span>{lineNumberError?.message}</span>
</div>
</FormItem>
)} />

{/*number of seats block*/}
<FormField name="seatingCount" render={({ field }) => (
<FormItem>
<FormControl>
<div className="flex items-center justify-between gap-5">
<Label htmlFor="seatingCount" className="text-background text-nowrap font-semibold">Koltuk
Sayısı:</Label>
<Input
id="seatingCount"
placeholder="Koltuk Sayısı"
type="number"
min={0}
max={999}
{...field}
onChange={(e) => field.onChange(Number(e.target.value))}
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)} />

<hr />
<span className="font-bold text-white block text-center">Başvurunun Yapıldığı Konum</span>
{/*application location box*/}
<div className="grid grid-cols-2 gap-2">
<FormField name="sourceCity" render={({ field }) => (
<FormItem>
<FormControl>
<SelectLocation
type="city"
value={field.value}
onChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)} />

<FormField name="sourceDistrict" render={({ field }) => (
<FormItem>
<FormControl>
<SelectLocation
type="district"
cityValue={form.watch('sourceCity')}
value={field.value}
onChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)} />
</div>

<FormField name="address" render={({ field }) => (
<FormItem>
<FormControl>
<Textarea {...field} placeholder="Açık adres" />
</FormControl>
<FormMessage />
</FormItem>
)} />

<hr />
<span className="font-bold text-white block text-center">Tahliye Sağlanacak Konum</span>

{/*target location box*/}
<div className="grid grid-cols-2 gap-2">
<FormField name="targetCity" render={({ field }) => (
<FormItem>
<FormControl>
<SelectLocation
type="city"
value={field.value}
onChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)} />

<FormField name="targetDistrict" render={({ field }) => (
<FormItem>
<FormControl>
<SelectLocation
type="district"
cityValue={form.watch('targetCity')}
value={field.value}
onChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)} />
</div>

<div className="grid grid-cols-2 gap-2">
<Button disabled={loading} onClick={prevStep} className="!bg-submitBlue w-full text-lg">
Geri
</Button>
<Button disabled={loading} type="submit" className="!bg-submitBlue w-full text-lg">
{loading ? 'Gönderiliyor...' : 'Gönder'}
</Button>
</div>
</>
}
</form>
</Form>
)
}
Loading
Loading