Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] 공홈 어드민 지원하기 페이지 퍼블리싱 #130

Merged
merged 14 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3,947 changes: 2,010 additions & 1,937 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file modified .yarn/install-state.gz
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@sopt-makers/colors": "^3.0.1",
"@sopt-makers/fonts": "^2.0.1",
"@sopt-makers/icons": "^1.0.4",
"@sopt-makers/ui": "^2.0.0",
"@sopt-makers/ui": "^2.4.4",
"axios": "^1.3.4",
"dayjs": "^1.11.9",
"eslint-config-next": "^14.1.4",
Expand All @@ -30,6 +30,7 @@
"react": "^18.2.0",
"react-datepicker": "^6.5.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.10",
"react-hook-form": "^7.53.0",
"react-query": "^3.39.3",
"recoil": "^0.7.7",
Expand Down
12 changes: 0 additions & 12 deletions src/components/org/OrgAdmin/CommonSection/BrandingColor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useState } from 'react';
import { useFormContext } from 'react-hook-form';

import {
StDescription,
Expand All @@ -17,11 +16,6 @@ const BrandingColor = () => {
const [highColor, setHighColor] = useState('');
const [subGrayColor, setSubGrayColor] = useState('');

const {
register,
formState: { errors },
} = useFormContext();

return (
<StWrapper>
<StTitleWrapper>
Expand All @@ -34,24 +28,18 @@ const BrandingColor = () => {
id="keyColorMain"
colorValue={mainColor}
onSetColorValue={(val: string) => setMainColor(val)}
register={register}
error={errors.keyColorMain?.message as string}
/>
<ColorInputField
label="키컬러 (저명도)"
id="keyColorLow"
colorValue={lowColor}
onSetColorValue={(val: string) => setLowColor(val)}
register={register}
error={errors.keyColorLow?.message as string}
/>
<ColorInputField
label="키컬러 (고명도)"
id="keyColorHigh"
colorValue={highColor}
onSetColorValue={(val: string) => setHighColor(val)}
register={register}
error={errors.keyColorHigh?.message as string}
/>
<BrandingSubColor
subGrayColor={subGrayColor}
Expand Down
13 changes: 8 additions & 5 deletions src/components/org/OrgAdmin/CommonSection/ColorInputField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FieldValues, UseFormRegister } from 'react-hook-form';
import { useFormContext } from 'react-hook-form';

import { VALIDATION_CHECK } from '@/utils/org';

Expand All @@ -11,7 +11,6 @@ interface ColorInputFieldProps {
id: string;
colorValue: string;
onSetColorValue: (value: string) => void;
register: UseFormRegister<FieldValues>;
error?: string;
}

Expand All @@ -20,9 +19,13 @@ const ColorInputField = ({
id,
colorValue,
onSetColorValue,
register,
error,
}: ColorInputFieldProps) => {
const {
register,
formState: { errors },
} = useFormContext();

return (
<StInputBox>
<StInputLabel htmlFor={id}>{label}</StInputLabel>
Expand All @@ -37,8 +40,8 @@ const ColorInputField = ({
placeholder="ex. #ffffff"
value={colorValue}
onChange={(e) => onSetColorValue(e.target.value)}
isError={error != undefined}
errorMessage={error as string}
isError={errors[id]?.message != undefined}
errorMessage={errors[id]?.message as string}
/>
<StColorPreview
type="color"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useFormContext } from 'react-hook-form';
import { VALIDATION_CHECK } from '@/utils/org';

import {
StErrorMessage,
StInput,
StInputBox,
StInputLabel,
Expand All @@ -14,7 +15,6 @@ import {
} from '../style';
import {
StDateWrapper,
StErrorMessage,
StRadioBox,
StRadioLabel,
StRadioWrapper,
Expand Down
6 changes: 0 additions & 6 deletions src/components/org/OrgAdmin/CommonSection/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,6 @@ export const StInfoImg = styled.img`
color: ${colors.white};
`;

export const StErrorMessage = styled.p`
${fontsObject.LABEL_3_14_SB};

color: ${colors.error};
`;

export const StSubColorTitle = styled(StInputLabel)`
display: flex;
gap: 5px;
Expand Down
88 changes: 88 additions & 0 deletions src/components/org/OrgAdmin/MyDropzone/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
'use client';

import { type MouseEvent, useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
import type { UseFormReturn } from 'react-hook-form';

import { VALIDATION_CHECK } from '@/utils/org';

import { StErrorMessage } from '../style';
import {
StImgButton,
StImgButtonWrapper,
StImgIcon,
StImgPreview,
} from './style';

interface MyDropzoneProps {
method: UseFormReturn;
label: string;
}

const MyDropzone = ({ method, label }: MyDropzoneProps) => {
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const {
register,
setValue,
formState: { errors },
} = method;

const onDrop = useCallback(
(acceptedFiles: File[]) => {
const file = acceptedFiles[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
setPreviewUrl(reader.result as string);
setValue(label, reader.result, { shouldValidate: true });
};
reader.readAsDataURL(file);
}
},
[label, setValue],
);

const handleClick = (e: MouseEvent<HTMLInputElement>) => {
e.preventDefault();
};

const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: {
'image/jpeg': [],
'image/jpg': [],
'image/png': [],
},
});

return (
<StImgButtonWrapper>
<StImgButton
{...getRootProps({
onClick: handleClick, // input의 클릭 이벤트 핸들링
})}
isError={errors[label]?.message != undefined}>
<input
{...getInputProps()}
{...register(label, {
required: true && VALIDATION_CHECK.required.errorText,
})}
/>
{previewUrl ? (
<StImgPreview src={previewUrl} alt="공홈 지원하기 탭 헤더 이미지" />
eonseok-jeon marked this conversation as resolved.
Show resolved Hide resolved
) : isDragActive ? (
<p>이미지를 드래그 해주세요...</p>
) : (
<StImgIcon />
)}
</StImgButton>
{errors[label] && (
<StErrorMessage>
<>{errors[label].message}</>
</StErrorMessage>
)}
</StImgButtonWrapper>
);
};

export default MyDropzone;
43 changes: 43 additions & 0 deletions src/components/org/OrgAdmin/MyDropzone/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import styled from '@emotion/styled';
import { colors } from '@sopt-makers/colors';
import { fontsObject } from '@sopt-makers/fonts';
import { IconImagePlus } from '@sopt-makers/icons';

export const StImgButtonWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 10px;
`;

interface StImgButtonProps {
isError: boolean;
}

export const StImgButton = styled.div<StImgButtonProps>`
${fontsObject.BODY_2_16_M}

display: flex;
align-items: center;
justify-content: center;
width: 547px;
height: 166px;
margin-top: 13px;
color: ${colors.white};
background-color: ${colors.gray800};
border: ${({ isError }) => (isError ? `1px solid ${colors.error}` : 'none')};
border-radius: 10px;
cursor: pointer;
`;

export const StImgIcon = styled(IconImagePlus)`
width: 24px;
height: 24px;
color: ${colors.white};
`;

export const StImgPreview = styled.img`
max-width: 547px;
height: 166px;
color: ${colors.white};
border-radius: 10px;
`;
17 changes: 17 additions & 0 deletions src/components/org/OrgAdmin/PartCategory/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Chip } from '@sopt-makers/ui';

import { PART_LIST } from '@/utils/org';

import { StPartCategoryWrapper } from './style';

const PartCategory = () => {
return (
<StPartCategoryWrapper>
{PART_LIST.map((part) => (
<Chip key={`${part}-${part}`}>{part}</Chip>
))}
</StPartCategoryWrapper>
);
};

export default PartCategory;
7 changes: 7 additions & 0 deletions src/components/org/OrgAdmin/PartCategory/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styled from '@emotion/styled';

export const StPartCategoryWrapper = styled.div`
display: flex;
gap: 6px;
align-items: center;
`;
108 changes: 108 additions & 0 deletions src/components/org/OrgAdmin/RecruitSection/Fna.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useFormContext } from 'react-hook-form';

import { VALIDATION_CHECK } from '@/utils/org';

import PartCategory from '../PartCategory';
import { StTextArea, StTitle, StTitleWrapper, StWrapper } from '../style';
import { StFnaWrapper, StTextAreaWrapper } from './style';

const Fna = () => {
const {
register,
formState: { errors },
} = useFormContext();

return (
<StWrapper>
<StTitleWrapper>
<StTitle>자주 묻는 질문</StTitle>
</StTitleWrapper>
<PartCategory />
<StTextAreaWrapper>
<StFnaWrapper>
<StTextArea
{...register('frequentQuestion1', {
required: true && VALIDATION_CHECK.required.errorText,
})}
topAddon={{
labelText: '질문1',
}}
value=""
fixedHeight={74}
maxHeight={74}
placeholder="질문을 입력해주세요."
isError={errors.partCurriculum?.message != undefined}
errorMessage={errors.partCurriculum?.message as string}
/>
<StTextArea
{...register('frequentQuestionAnswer1', {
required: true && VALIDATION_CHECK.required.errorText,
})}
value=""
fixedHeight={74}
maxHeight={74}
placeholder="답변을 입력해주세요."
isError={errors.partCurriculum?.message != undefined}
errorMessage={errors.partCurriculum?.message as string}
/>
</StFnaWrapper>
<StFnaWrapper>
<StTextArea
{...register('frequentQuestion2', {
required: true && VALIDATION_CHECK.required.errorText,
})}
topAddon={{
labelText: '질문2',
}}
value=""
fixedHeight={74}
maxHeight={74}
placeholder="질문을 입력해주세요."
isError={errors.partCurriculum?.message != undefined}
errorMessage={errors.partCurriculum?.message as string}
/>
<StTextArea
{...register('frequentQuestionAnswer2', {
required: true && VALIDATION_CHECK.required.errorText,
})}
value=""
fixedHeight={74}
maxHeight={74}
placeholder="답변을 입력해주세요."
isError={errors.partCurriculum?.message != undefined}
errorMessage={errors.partCurriculum?.message as string}
/>
</StFnaWrapper>
<StFnaWrapper>
<StTextArea
{...register('frequentQuestion3', {
required: true && VALIDATION_CHECK.required.errorText,
})}
topAddon={{
labelText: '질문3',
}}
value=""
fixedHeight={74}
maxHeight={74}
placeholder="질문을 입력해주세요."
isError={errors.partCurriculum?.message != undefined}
errorMessage={errors.partCurriculum?.message as string}
/>
<StTextArea
{...register('frequentQuestionAnswer3', {
required: true && VALIDATION_CHECK.required.errorText,
})}
value=""
fixedHeight={74}
maxHeight={74}
placeholder="답변을 입력해주세요."
isError={errors.partCurriculum?.message != undefined}
errorMessage={errors.partCurriculum?.message as string}
/>
</StFnaWrapper>
</StTextAreaWrapper>
</StWrapper>
);
};

export default Fna;
Loading