Skip to content

Commit

Permalink
Merge pull request #37 from primus-teoSprint/feat/#32
Browse files Browse the repository at this point in the history
[#32][#34] textarea ์™€ recoil ๋™๊ธฐํ™” ๋ฐ ์ž‘์„ฑ ํผ ์ œ์ถœ๊นŒ์ง€์˜ ๋กœ์ง ๊ตฌํ˜„
  • Loading branch information
03hoho03 authored Apr 7, 2024
2 parents 44bdf5e + 405e718 commit 25c2e65
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 85 deletions.
11 changes: 9 additions & 2 deletions app/(route)/verification/ibulsin/_components/Step1/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@

import Link from 'next/link'
import Textarea from '../Textarea'
import { ibulsinVariants } from '@/app/_constants/ibulsin'
import {
outlineTextareaAtom,
whyTextareaAtom,
} from '@/app/_store/ibulsin/textarea'
import style from './index.module.css'

function Step1() {
const { outline, why } = ibulsinVariants

return (
<div className={style.main_container}>
<div className={style.step_info}>
Expand All @@ -22,14 +29,14 @@ function Step1() {
์ƒ๊ฐํ•œ ์•„์ด๋””์–ด๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์ž‘์„ฑํ•ด๋ด์š”! ์ด๊ณณ์—์„œ๋Š” ์˜ค๋กœ์ง€
์•„์ด๋””์–ด์—๋งŒ ์ง‘์ค‘ํ•ด์š”.
</p>
<Textarea fieldKey={'outline'} />
<Textarea fieldKey={outline} atom={outlineTextareaAtom} />
</div>
<div className={style.input_container}>
<h3 className={style.input_title}>์ƒ๊ฐํ•˜๊ฒŒ ๋œ ๋ฐฐ๊ฒฝ</h3>
<p className={style.input_explain}>
ํ•ด๋‹น ์•„์ด๋””์–ด๋ฅผ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜๊ฒŒ ๋˜์—ˆ๋‚˜์š”?
</p>
<Textarea fieldKey={'why'} />
<Textarea fieldKey={why} atom={whyTextareaAtom} />
</div>
<div className={style.direction_btns}>
<Link
Expand Down
14 changes: 12 additions & 2 deletions app/(route)/verification/ibulsin/_components/Step2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,15 @@ import S from './index.module.css'
import Link from 'next/link'
import Textarea from '../Textarea'
import MoreExplainBtn from '../MoreExplainBtn'
import { ibulsinVariants } from '@/app/_constants/ibulsin'
import {
XYZTextareaAtom,
marketResponseTextareaAtom,
} from '@/app/_store/ibulsin/textarea'

function Step2() {
const { marketResponse, XYZ } = ibulsinVariants

return (
<div className={S.main_container}>
<div className={S.step_info}>
Expand All @@ -28,7 +35,10 @@ function Step2() {
์•„์ด๋””์–ด๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐ›์•„๋“ค์ผ์ง€์— ๋Œ€ํ•œ ์šฐ๋ฆฌ์˜ ํ•ต์‹ฌ ์‹ ๋…์ด๋‚˜ ๊ฐ€์ •์„
์–˜๊ธฐํ•ด์š”.
</p>
<Textarea fieldKey={'marketResponse'} />
<Textarea
fieldKey={marketResponse}
atom={marketResponseTextareaAtom}
/>
</div>
<div className={S.input_container}>
<div className={S.input_title_container}>
Expand All @@ -39,7 +49,7 @@ function Step2() {
์ ์–ด๋„ Xํผ์„ผํŠธ์˜ Y๋Š” Z ํ•  ๊ฒƒ์ด๋‹ค ๋ผ๋Š” ํ˜•ํƒœ์˜ ๊ฐ€์„ค์ด์—์š”. ์‹œ์žฅํ˜ธ์‘
๊ฐ€์„ค์„ ๋ฐ”ํƒ•์œผ๋กœ ์ˆซ์ž๋กœ ์น˜ํ™˜์— ์ข€ ๋” ์น˜๋ฐ€ํ•˜๊ฒŒ ํ•˜๋Š” ๋„๊ตฌ์˜ˆ์š”
</p>
<Textarea fieldKey={'XYZ'} />
<Textarea fieldKey={XYZ} atom={XYZTextareaAtom} />
</div>
<div className={S.direction_btns}>
<Link className={S.prev_btn} href={'/verification/ibulsin?step=1'}>
Expand Down
63 changes: 51 additions & 12 deletions app/(route)/verification/ibulsin/_components/Step3/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,58 @@
'use client'

import { ibulsinVariants } from '@/app/_constants/ibulsin'
import React from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import MoreExplainBtn from '../MoreExplainBtn'
import { ibulsinVariants } from '@/app/_constants/ibulsin'
import {
pretotypingTextareaAtom,
xyzTextareaAtom,
} from '@/app/_store/ibulsin/textarea'
import useIbulsinData from '@/app/_hooks/useIbulsinData'
import Textarea from '../Textarea'
import S from './index.module.css'
import useIbulsinFormMutation from '@/app/_service/mutations/useIbulsinForm'
import { useRouter } from 'next/navigation'

function Step3() {
const { xyz, pretotyping } = ibulsinVariants
const router = useRouter()
const { xyz, pretotyping } = ibulsinVariants
const {
outlineValue,
whyTextValue,
marketResponseValue,
XYZValue,
xyzValue,
pretotypingValue,
} = useIbulsinData()
const { mutate } = useIbulsinFormMutation()

const handleSubmit = () => {
const ideaOverView = outlineValue
const thinkBackground = whyTextValue
const marketTheory = marketResponseValue
const bigxyzTheory = XYZValue
const smallxyzTheory = xyzValue
const pretotypingTheory = pretotypingValue

const body = {
ideaOverView,
thinkBackground,
marketTheory,
bigxyzTheory,
smallxyzTheory,
pretotypingTheory,
}

mutate(body, {
onSuccess: () => {
router.push('/')
},
onError: () => {
alert('์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค.')
},
})
}

return (
<div className={S.main_container}>
Expand All @@ -31,12 +74,12 @@ function Step3() {
XYZ ๋ฒ•์น™์œผ๋กœ ํ‘œํ˜„๋œ ์‹œ์žฅ ํ˜ธ์‘ ๊ฐ€์„ค์˜ ๋ฒ”์œ„๋ฅผ ์ž˜๊ฒŒ ์ชผ๊ฐœ xyz๋ฒ•์น™์œผ๋กœ
ํ‘œํ˜„ํ•ด๋ณด์„ธ์š”.
</p>
<Textarea fieldKey={xyz} />
<Textarea fieldKey={xyz} atom={xyzTextareaAtom} />
</div>
<div className={S.input_container}>
<div className={S.flex_between_wrapper}>
<div className={S.flex_wrapper}>
<h3 className={S.input_title}>ํ”„๋กœํ†  ํƒ€์ดํ•‘ ๊ณ„ํš</h3>
<h3 className={S.input_title}>ํ”„๋ฆฌํ†  ํƒ€์ดํ•‘ ๊ณ„ํš</h3>
<MoreExplainBtn type={pretotyping} />
</div>
</div>
Expand All @@ -46,18 +89,14 @@ function Step3() {
๋‹ค๋ฅด๊ฒŒ ์‹œ์ œํ’ˆ์ด ์—†์–ด๋„ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ๋งŒ๋“ค์–ด ๊ฐ€์„ค์„ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•์ด์—์š”.
`}
</p>
<Textarea fieldKey={pretotyping} />
<Textarea fieldKey={pretotyping} atom={pretotypingTextareaAtom} />
</div>
<div className={S.direction_btns}>
<Link className={S.prev_btn} href={'/verification/ibulsin?step=2'}>
์ด์ „ ๋‹จ๊ณ„
</Link>
<button
className={S.next_btn}
type="button"
onClick={() => router.push('/mypage')}
>
์ œ์ถœํ•˜๊ธฐ
<button className={S.next_btn} type="button" onClick={handleSubmit}>
์ œ์ถœ ํ•˜๊ธฐ
</button>
</div>
</div>
Expand Down
84 changes: 16 additions & 68 deletions app/(route)/verification/ibulsin/_components/Textarea/index.tsx
Original file line number Diff line number Diff line change
@@ -1,91 +1,39 @@
'use client'

import cn from 'classnames'
import { useForm } from 'react-hook-form'

import S from './index.module.css'
import { RecoilState } from 'recoil'
import { RegisterOptions } from 'react-hook-form'
import { useFormCustom } from '@/app/_hooks/useFormWithRecoil'

interface TextAreaProps {
fieldKey: 'outline' | 'why' | 'marketResponse' | 'XYZ' | 'xyz' | 'pretotyping'
atom: RecoilState<string>
option?: RegisterOptions
}

function Textarea({ fieldKey }: TextAreaProps) {
const { register, watch } = useForm()

const outlineField = register('outline', {
required: '',
maxLength: { value: 500, message: '์ตœ๋Œ€ 500์ž๊นŒ์ง€ ์ž‘์„ฑ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.' },
})
const whyField = register('why', {
required: '',
maxLength: { value: 500, message: '์ตœ๋Œ€ 500์ž๊นŒ์ง€ ์ž‘์„ฑ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.' },
})
const marketResponseField = register('marketResponse', {
required: '',
maxLength: { value: 500, message: '์ตœ๋Œ€ 500์ž๊นŒ์ง€ ์ž‘์„ฑ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.' },
})
const XYZField = register('XYZ', {
required: '',
maxLength: { value: 500, message: '์ตœ๋Œ€ 500์ž๊นŒ์ง€ ์ž‘์„ฑ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.' },
})
const xyzField = register('xyz', {
required: '',
maxLength: { value: 500, message: '์ตœ๋Œ€ 500์ž๊นŒ์ง€ ์ž‘์„ฑ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.' },
})
const pretotypingField = register('pretotyping', {
required: '',
maxLength: { value: 500, message: '์ตœ๋Œ€ 500์ž๊นŒ์ง€ ์ž‘์„ฑ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.' },
})

const fields = {
outline: {
register: outlineField,
MaxLength: 500,
},
why: {
register: whyField,
MaxLength: 500,
},
marketResponse: {
register: marketResponseField,
MaxLength: 500,
},
XYZ: {
register: XYZField,
MaxLength: 500,
},
xyz: {
register: xyzField,
MaxLength: 500,
},
pretotyping: {
register: pretotypingField,
MaxLength: 500,
},
}
function Textarea({ fieldKey, atom, option }: TextAreaProps) {
const { field, countCharacters, handleChange } = useFormCustom(
fieldKey,
atom,
option,
)

const countCharacters = () => {
const content = watch(fieldKey)
if (!content) {
return 0
}
return content.length
}
const MAX_LENGTH = 500

return (
<div className={S.textarea_container}>
<textarea
{...fields[fieldKey].register}
maxLength={fields[fieldKey].MaxLength - 1}
/>
<textarea {...field} maxLength={MAX_LENGTH} onChange={handleChange} />
<div className={S.letter_count_container}>
<span
className={cn({
[S.letter_max]: countCharacters() >= fields[fieldKey].MaxLength,
[S.letter_max]: countCharacters() >= MAX_LENGTH,
})}
>
{countCharacters()}
</span>
<span>{`/${fields[fieldKey].MaxLength}`}</span>
<span>{`/${MAX_LENGTH}`}</span>
</div>
</div>
)
Expand Down
2 changes: 1 addition & 1 deletion app/_constants/ibulsin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface ibulsinVariantsType {
export interface ibulsinVariantsType {
outline: 'outline'
why: 'why'
marketResponse: 'marketResponse'
Expand Down
37 changes: 37 additions & 0 deletions app/_hooks/useFormWithRecoil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { RegisterOptions, useForm } from 'react-hook-form'
import { ChangeEventHandler, useEffect } from 'react'
import { RecoilState, useRecoilState } from 'recoil'

export const useFormCustom = (
key: string,
atom: RecoilState<string>,
option: RegisterOptions | undefined,
) => {
const { register, setValue, watch } = useForm()
const [recoilState, setRecoilState] = useRecoilState(atom)

const defaultOption = {
required: '',
maxLength: { value: 500, message: '์ตœ๋Œ€ 500์ž๊นŒ์ง€ ์ž‘์„ฑ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.' },
}

const field = register(key, option ?? defaultOption)

useEffect(() => {
setValue(key, recoilState)
}, [recoilState])

const countCharacters = () => {
const content = watch(key)

return content ? content.length : 0
}

const handleChange: ChangeEventHandler<HTMLTextAreaElement> = (e) => {
const { value } = e.target

setRecoilState(value)
}

return { field, countCharacters, handleChange }
}
29 changes: 29 additions & 0 deletions app/_hooks/useIbulsinData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useRecoilValue } from 'recoil'
import {
outlineTextareaAtom,
whyTextareaAtom,
marketResponseTextareaAtom,
XYZTextareaAtom,
xyzTextareaAtom,
pretotypingTextareaAtom,
} from '@/app/_store/ibulsin/textarea'

function useIbulsinData() {
const outlineValue = useRecoilValue(outlineTextareaAtom)
const whyTextValue = useRecoilValue(whyTextareaAtom)
const marketResponseValue = useRecoilValue(marketResponseTextareaAtom)
const XYZValue = useRecoilValue(XYZTextareaAtom)
const xyzValue = useRecoilValue(xyzTextareaAtom)
const pretotypingValue = useRecoilValue(pretotypingTextareaAtom)

return {
outlineValue,
whyTextValue,
marketResponseValue,
XYZValue,
xyzValue,
pretotypingValue,
}
}

export default useIbulsinData
27 changes: 27 additions & 0 deletions app/_service/mutations/useIbulsinForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import axiosInstance from '@/app/_utils/axios'
import { useMutation } from '@tanstack/react-query'

interface IbulsinFormBodyType {
ideaOverView: string
thinkBackground: string
marketTheory: string
bigxyzTheory: string
smallxyzTheory: string
pretotypingTheory: string
}

const postForm = (data: IbulsinFormBodyType) => {
const response = axiosInstance.post(`/api/`, data)

return response
}

const useIbulsinFormMutation = () => {
const { mutate } = useMutation({
mutationFn: postForm,
})

return { mutate }
}

export default useIbulsinFormMutation
Loading

0 comments on commit 25c2e65

Please sign in to comment.