Skip to content

Commit

Permalink
[#60] feat: add create question form (#62)
Browse files Browse the repository at this point in the history
* feat: add use form

* feat: add form and use form in widget

* feat: add submit and and client pages

* feat: add client render page
  • Loading branch information
dohui-son authored Aug 17, 2024
1 parent 3c50b20 commit 3433fc4
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 29 deletions.
120 changes: 120 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/client/app/(withLayout)/question/create/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { QuestionCreateInputs } from '@widgets/QuestionCreateInputs'
import { ClientQuestionCreatePage } from 'src/pages/questionCreate'

export default function QuestionCreatePage() {
return (
<div>
<QuestionCreateInputs />
<ClientQuestionCreatePage />
</div>
)
}
3 changes: 3 additions & 0 deletions packages/client/src/entities/question/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { useCreateQuestionForm } from './lib/useQuestionCreateForm'

export type { QuestionFormValues } from './lib/useQuestionCreateForm'
21 changes: 21 additions & 0 deletions packages/client/src/entities/question/lib/useQuestionCreateForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useForm, UseFormReturn } from 'react-hook-form'

export type QuestionFormValues = {
title: string
content: string
jobCategory: null | { label: string; id: string }
reward: number
}

export const useCreateQuestionForm = (): UseFormReturn<QuestionFormValues> => {
const form = useForm({
mode: 'onTouched',
defaultValues: {
title: '',
content: '',
jobCategory: null,
reward: 1000,
},
})
return form as UseFormReturn<QuestionFormValues>
}
55 changes: 55 additions & 0 deletions packages/client/src/entities/question/lib/useValidateQuestion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { UseFormReturn, useWatch } from 'react-hook-form'
import { QuestionFormValues } from './useQuestionCreateForm'

export const useValidateQuestion = (
form: UseFormReturn<QuestionFormValues>,
) => {
const { title, content, jobCategory, reward } = useWatch({
control: form.control,
})

const isTitleValid = !!title && title?.length > 0 && title?.length <= 20
const isContentValid =
!!content && content?.length > 0 && content?.length <= 500
const isCategoryValid =
jobCategory !== null &&
!!jobCategory?.id &&
!!jobCategory?.label &&
typeof jobCategory?.id === 'string' &&
typeof jobCategory?.label === 'string'
const isRewardValid = !!reward && reward >= 1000 && reward <= 100000

const getTitleErrorMessage = () => {
if (!isTitleValid) {
return '제목은 1자 이상 20자 이하로 작성해주세요'
}
return ''
}
const getContentErrorMessage = () => {
if (!isContentValid) {
return '내용은 1자 이상 500자 이하로 작성해주세요'
}
return ''
}
const getJobCategoryErrorMessage = () => {
if (!isCategoryValid) {
return '직군을 선택해주세요'
}
return ''
}
const getRewardErrorMessage = () => {
if (!isRewardValid) {
return '보상은 1,000원 이상 10,000원 이하로 설정해주세요'
}
return ''
}

return {
getTitleErrorMessage,
getContentErrorMessage,
getJobCategoryErrorMessage,
getRewardErrorMessage,
canSubmit:
isTitleValid && isContentValid && isCategoryValid && isRewardValid,
}
}
1 change: 1 addition & 0 deletions packages/client/src/pages/questionCreate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ClientQuestionCreatePage } from './ui/Page'
16 changes: 16 additions & 0 deletions packages/client/src/pages/questionCreate/ui/Page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use client'

import { useCreateQuestionForm } from '@entities/question'
import { QuestionCreateInputs } from '@widgets/QuestionCreateInputs'

export function ClientQuestionCreatePage() {
const form = useCreateQuestionForm()
// api 연동시 onSubmit 함수 구현

return (
<QuestionCreateInputs
form={form}
onSubmit={() => alert('TODO: submit')}
/>
)
}
22 changes: 22 additions & 0 deletions packages/client/src/pages/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# pages of FSD Architecture for client render

- use app/page.tsx or app/(withLayout)/\*/page.tsx of app router
- the 2nd highest layer of FSD layers
- application pages (e.g. /signin , /home)
- can import from all layers (only form index files in each folder for encapsulation)
- a little bit different from pages from FSD

# Layer priorities

1. apps (same as app in the FSD)
2. pages ✅
3. widgets
4. features
5. entities
6. shared

# Reference

- [FSD official docs](https://feature-sliced.design/docs)
- [ko tech article](https://emewjin.github.io/feature-sliced-design/)
- [example](https://nukeapp.netlify.app/)
Loading

0 comments on commit 3433fc4

Please sign in to comment.