Skip to content

Commit

Permalink
πŸ’„ 곡고 생성 μ‹œ 직업 선택 ν•„λ“œ μŠ€νƒ€μΌλ§ (#268)
Browse files Browse the repository at this point in the history
### πŸ“ μž‘μ—… λ‚΄μš©

- 곡고 생성 μ‹œ 직업 선택 ν•„λ“œλ₯Ό μŠ€νƒ€μΌλ§ν–ˆμŠ΅λ‹ˆλ‹€.
- select λŒ€μ‹  μ»€μŠ€ν…€ ν•„λ“œλ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
  • Loading branch information
Yeonu-Kim authored Jan 31, 2025
1 parent 957ba61 commit e7dd82d
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 137 deletions.
8 changes: 8 additions & 0 deletions apps/client/public/svg/calendar_today.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions apps/client/src/entities/asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export const ICON_SRC = {
SELECTED: '/svg/bookmark_selected.svg',
UNSELECTED: '/svg/bookmark_unselected.svg',
},
CALENDAR: '/svg/calendar_today.svg',
};
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const InvestAmountField = ({
}}
className="w-[190px]"
/>
<span>{unit}</span>
<span className="text-grey-dark-hover">{unit}</span>
</div>
<div className="flex flex-col gap-1">
{infoMessage !== undefined && (
Expand Down
253 changes: 117 additions & 136 deletions apps/client/src/feature/post/ui/CreatePostForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,33 @@ import { useState } from 'react';
import { MarkdownEditorField } from '@/components/field/MarkdownEditorField';
import { StringField } from '@/components/field/StringField';
import { FormContainer } from '@/components/form';
import { TextInput } from '@/components/input';
import { LabelContainer } from '@/components/input/LabelContainer';
import { CancelCheckModal } from '@/components/modal/CancelCheckModal';
import { RewritePostModal } from '@/components/modal/RewritePostModal';
import { FormErrorResponse } from '@/components/response/formResponse';
import { Button } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import { ICON_SRC } from '@/entities/asset';
import { createErrorMessage } from '@/entities/errors';
import type { CreatePostRequest } from '@/entities/post';
import type { JobMajorCategory, JobMinorCategory } from '@/entities/post';
import type { JobMajorCategory } from '@/entities/post';
import { JOB_CATEGORY_MAP, JOB_MAJOR_CATEGORIES } from '@/entities/post';
import { postFormPresentation } from '@/feature/post/presentation/postFormPresentation';
import {
CONTENT_MAX_LENGTH,
postInputPresentation,
} from '@/feature/post/presentation/postInputPresentation';
import { EmploymentEndDateField } from '@/feature/post/ui/field/EmploymentEndDateField';
import { HeadcountField } from '@/feature/post/ui/field/HeadcountField';
import { useGuardContext } from '@/shared/context/hooks';
import { ServiceContext } from '@/shared/context/ServiceContext';
import { TokenContext } from '@/shared/context/TokenContext';
import { useRouteNavigation } from '@/shared/route/useRouteNavigation';
import { formatMajorJobToLabel, formatMinorJobToLabel } from '@/util/format';

export const CreatePostForm = ({ companyId }: { companyId: string }) => {
const [showCalendar, setShowCalendar] = useState(false);
const [showFilter, setShowFilter] = useState<
'NONE' | 'CALENDAR' | 'CATEGORY'
>('NONE');
const [isSubmit, setIsSubmit] = useState(false);
const [showModal, setShowModal] = useState<'NONE' | 'CANCEL' | 'NEXT'>(
'NONE',
Expand Down Expand Up @@ -99,157 +102,135 @@ export const CreatePostForm = ({ companyId }: { companyId: string }) => {
input={title}
isPending={isPending}
isSubmit={isSubmit}
isSubmitError={title.isError}
isSubmitError={formStates.title.isError}
placeholder="λͺ¨μ§‘ 직무 이름을 ꡬ체적으둜 μž‘μ„±ν•΄μ£Όμ„Έμš”. (e.g. React ν”„λ‘ νŠΈμ—”λ“œ 개발자)"
errorMessage="곡고λͺ…은 500자 μ΄λ‚΄λ‘œ μž‘μ„±ν•΄μ£Όμ„Έμš”."
required={true}
/>
<div>
<LabelContainer label="직무 μœ ν˜•" id="job">
<div>
<div>
<select
value={jobMajorCategory.value}
disabled={isPending}
onChange={(e) => {
jobMajorCategory.onChange(
e.target.value as JobMajorCategory,
);
}}
<div className="flex w-full gap-2">
<div className="flex-1">
<LabelContainer label="직무 μœ ν˜•" id="job" required>
<Button
onClick={(e) => {
e.preventDefault();
if (showFilter !== 'CATEGORY') {
setShowFilter('CATEGORY');
return;
}
setShowFilter('NONE');
}}
variant="outline"
className="w-full justify-between"
>
{jobMinorCategory.value !== 'NONE'
? formatMinorJobToLabel(jobMinorCategory.value)
: '직무λ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”.'}
<img
src={ICON_SRC.ARROW}
className={`${showFilter === 'CATEGORY' ? 'rotate-180' : 'rotate-0'} transition-rotate ease-in-out duration-300`}
/>
</Button>
<section className="relative">
<div
className={`absolute left-0 top-0 flex gap-2 w-[364px] z-50 rounded-lg bg-white shadow-lg overflow-hidden transition-all duration-300 ${
showFilter === 'CATEGORY'
? 'opacity-100 scale-100'
: 'opacity-0 pointer-events-none'
}`}
>
{JOB_MAJOR_CATEGORIES.map((category) => {
const label = formatMajorJobToLabel(category);
<div className="flex flex-col gap-2 w-[162px] px-2 border-r">
{JOB_MAJOR_CATEGORIES.map((category) => {
const label = formatMajorJobToLabel(category);

if (label === null) return null;
if (label === null) return null;

return (
<option
key={`major-category-${category}`}
value={category}
>
{formatMajorJobToLabel(category)}
</option>
);
})}
</select>
</div>
<div>
<select
value={jobMinorCategory.value}
disabled={isPending}
onChange={(e) => {
jobMinorCategory.onChange(
e.target.value as JobMinorCategory,
);
}}
>
<option value="NONE" selected disabled hidden></option>
{JOB_CATEGORY_MAP[jobMajorCategory.value].map(
(subCategory) => (
<option
key={`sub-category-${subCategory}`}
value={subCategory}
>
{formatMinorJobToLabel(subCategory)}
</option>
),
)}
</select>
</div>
</div>
{isSubmit && jobMinorCategory.isError && (
<p>직무λ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”.</p>
)}
</LabelContainer>
<LabelContainer label="λͺ¨μ§‘ 인원" id="headcount">
<TextInput
value={headcount.value}
disabled={isPending}
onChange={(e) => {
headcount.onChange(e.target.value);
}}
return (
<Button
variant="ghost"
key={`major-category-${category}`}
onClick={(e) => {
e.preventDefault();
jobMajorCategory.onChange(
category as JobMajorCategory,
);
}}
className={`text-grey-darker justify-start ${jobMajorCategory.value === category ? 'bg-grey-light font-bold' : ''}`}
>
{formatMajorJobToLabel(category)}
</Button>
);
})}
</div>
<div className="flex flex-col gap-2 w-[202px]">
{JOB_CATEGORY_MAP[jobMajorCategory.value].map(
(subCategory) => (
<Button
variant="ghost"
key={`sub-category-${subCategory}`}
value={subCategory}
onClick={(e) => {
e.preventDefault();
jobMinorCategory.onChange(subCategory);
}}
className={`text-grey-darker justify-start ${jobMinorCategory.value === subCategory ? 'bg-grey-light font-bold' : ''}`}
>
{formatMinorJobToLabel(subCategory)}
</Button>
),
)}
</div>
</div>
</section>
{isSubmit && jobMinorCategory.isError && (
<p>직무λ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”.</p>
)}
</LabelContainer>
</div>
<div className="flex-2">
<HeadcountField
label="λͺ¨μ§‘ 인원"
input={headcount}
unit="λͺ…"
isPending={isPending}
isSubmit={isSubmit}
isSubmitError={formStates.headcount.isError}
errorMessage={'λͺ¨μ§‘ 인원은 0 λ˜λŠ” μ–‘μ˜ μ •μˆ˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.'}
placeholder="λͺ¨μ§‘ 인원 수"
required={true}
/>
{isSubmit && formStates.headcount.isError && (
<p>λͺ¨μ§‘ 인원은 0 λ˜λŠ” μ–‘μ˜ μ •μˆ˜μ—¬μ•Ό ν•©λ‹ˆλ‹€.</p>
)}
</LabelContainer>
</div>
</div>
<MarkdownEditorField
label="상세 곡고 κΈ€"
input={detail}
maxLength={CONTENT_MAX_LENGTH}
isPending={isPending}
isSubmit={isSubmit}
isSubmitError={detail.isError}
isSubmitError={formStates.detail.isError}
errorMessage={`곡고 글은 ${CONTENT_MAX_LENGTH}자 μ΄λ‚΄λ‘œ μž‘μ„±ν•΄μ£Όμ„Έμš”.`}
required={true}
/>
<LabelContainer label="μ±„μš© 마감일" id="employmentEndDate">
<div className="relative">
<div
className={`absolute left-0 bottom-0 mt-2 w-[340px] rounded-lg bg-white shadow-lg overflow-hidden transition-all duration-300 ${
showCalendar
? 'opacity-100 scale-100'
: 'opacity-0 pointer-events-none'
}`}
>
<Calendar
mode="single"
selected={new Date(employmentEndDate.value)}
onSelect={(input: Date | undefined) => {
employmentEndDate.onChange(
input !== undefined
? new Date(input)
.toLocaleDateString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\. /g, '-')
.replace('.', '')
: '',
);
}}
/>
</div>
</div>
<Button
onClick={(e) => {
e.preventDefault();
setShowCalendar(!showCalendar);
}}
variant="outline"
className="w-full justify-start"
>
{employmentEndDate.value !== ''
? new Date(employmentEndDate.value)
.toLocaleDateString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\. /g, '-')
.replace('.', '')
: 'λͺ¨μ§‘ λ§ˆκ°μΌμ„ μ„ νƒν•΄μ£Όμ„Έμš”.'}
</Button>

<input
id="employmentEndDate"
type="date"
value={employmentEndDate.value}
disabled={isPending}
onChange={(e) => {
employmentEndDate.onChange(e.target.value);
}}
/>
{isSubmit && formStates.employmentEndDateTime.isError && (
<p>μ˜¬λ°”λ₯Έ μ±„μš© λ§ˆκ°μΌμ„ μ„ νƒν•΄μ£Όμ„Έμš”.</p>
)}
{responseMessage !== '' && (
<FormErrorResponse>{responseMessage}</FormErrorResponse>
)}
</LabelContainer>
<EmploymentEndDateField
label="μ±„μš© 마감일"
showFilter={showFilter}
onClick={() => {
if (showFilter !== 'CALENDAR') {
setShowFilter('CALENDAR');
return;
}
setShowFilter('NONE');
}}
input={employmentEndDate}
isPending={isPending}
isSubmit={isSubmit}
isSubmitError={formStates.employmentEndDateTime.isError}
infoMessage={`μ±„μš© λ§ˆκ°μΌμ„ μ„€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ 'μƒμ‹œ' μƒνƒœλ‘œ λ“±λ‘λΌμš”.`}
errorMessage="μ˜¬λ°”λ₯Έ μ±„μš© λ§ˆκ°μΌμ„ μ„ νƒν•΄μ£Όμ„Έμš”."
required={true}
/>
{responseMessage !== '' && (
<FormErrorResponse>{responseMessage}</FormErrorResponse>
)}
<div className="flex gap-2">
<Button
variant="secondary"
Expand Down
1 change: 1 addition & 0 deletions apps/client/src/feature/post/ui/PostDetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const PostDetailView = ({ postId }: { postId: string }) => {

const investCompanyList = investCompany.split(',');
const tagList = tags?.map((item) => item.tag);
console.log(tagList);

return (
<div className="max-w-screen-md mx-auto gap-12 p-10 flex">
Expand Down
Loading

0 comments on commit e7dd82d

Please sign in to comment.