diff --git a/src/components/org/OrgAdmin/AboutSection/index.tsx b/src/components/org/OrgAdmin/AboutSection/index.tsx index f4c3a4a7..8c7d5b4c 100644 --- a/src/components/org/OrgAdmin/AboutSection/index.tsx +++ b/src/components/org/OrgAdmin/AboutSection/index.tsx @@ -23,11 +23,13 @@ import Schedule from './Schedule'; interface AboutSectionProps { selectedExec: EXEC_TYPE; onChangeSelectedExec: (member: EXEC_TYPE) => void; + onEditModeChange: (isEditing: boolean) => void; } const AboutSectionContent = ({ selectedExec, onChangeSelectedExec, + onEditModeChange, }: AboutSectionProps) => { const [editStep, setEditStep] = useState(EDIT_STEP.VIEW); @@ -39,6 +41,7 @@ const AboutSectionContent = ({ getValues, setValue, setError, + setFocus, clearErrors, formState: { isDirty }, } = useFormContext(); @@ -47,6 +50,10 @@ const AboutSectionContent = ({ const isDeployModalOpen = editStep === EDIT_STEP.DEPLOY; const hasUnsavedChanges = isEditMode && isDirty; + useEffect(() => { + onEditModeChange(isEditMode); + }, [isEditMode, onEditModeChange]); + useEffect(() => { syncAboutFormFromAdminData(data, setValue); }, [data, setValue]); @@ -79,6 +86,8 @@ const AboutSectionContent = ({ validationAboutInputs( getValues, setError, + setFocus, + onChangeSelectedExec, data?.headerImage, data?.coreValue, data?.member, diff --git a/src/components/org/OrgAdmin/CommonSection/index.tsx b/src/components/org/OrgAdmin/CommonSection/index.tsx index b09ccc41..3b144b88 100644 --- a/src/components/org/OrgAdmin/CommonSection/index.tsx +++ b/src/components/org/OrgAdmin/CommonSection/index.tsx @@ -22,6 +22,7 @@ import RecruitSchedule from './RecruitSchedule'; interface CommonSectionProps { group: Group; onChangeGroup: (group: Group) => void; + onEditModeChange: (isEditing: boolean) => void; } const COMMON_FIELD_NAMES = [ @@ -31,7 +32,11 @@ const COMMON_FIELD_NAMES = [ 'brandingColor', ]; -const CommonSectionContent = ({ group, onChangeGroup }: CommonSectionProps) => { +const CommonSectionContent = ({ + group, + onChangeGroup, + onEditModeChange, +}: CommonSectionProps) => { const [editStep, setEditStep] = useState(EDIT_STEP.VIEW); const [snapshot, setSnapshot] = useState(null); @@ -39,7 +44,7 @@ const CommonSectionContent = ({ group, onChangeGroup }: CommonSectionProps) => { const { mutate: deployCommon, isLoading: isDeploying } = useDeployCommonMutation(); - const { control, getValues, setValue, setError, clearErrors } = + const { control, getValues, setValue, setError, setFocus, clearErrors } = useFormContext(); const watchedValues = useWatch({ control, name: COMMON_FIELD_NAMES }); @@ -51,6 +56,10 @@ const CommonSectionContent = ({ group, onChangeGroup }: CommonSectionProps) => { snapshot !== null && JSON.stringify(watchedValues) !== JSON.stringify(snapshot); + useEffect(() => { + onEditModeChange(isEditMode); + }, [isEditMode, onEditModeChange]); + useEffect(() => { syncCommonFormFromAdminData(data, setValue); }, [data, setValue]); @@ -95,7 +104,9 @@ const CommonSectionContent = ({ group, onChangeGroup }: CommonSectionProps) => { onStartEdit={startEditMode} onCancel={cancelEditMode} onDeploy={() => { - if (validationCommonInputs(getValues, setError, onChangeGroup)) { + if ( + validationCommonInputs(getValues, setError, setFocus, onChangeGroup) + ) { setEditStep(EDIT_STEP.DEPLOY); } }} diff --git a/src/components/org/OrgAdmin/HomeSection/HomeSection.tsx b/src/components/org/OrgAdmin/HomeSection/HomeSection.tsx index 3a868421..56af27fc 100644 --- a/src/components/org/OrgAdmin/HomeSection/HomeSection.tsx +++ b/src/components/org/OrgAdmin/HomeSection/HomeSection.tsx @@ -34,7 +34,11 @@ type HomeDraft = { const EMPTY_REVIEWS: Review[] = []; const EMPTY_NEWS: News[] = []; -const HomeSectionContent = () => { +interface HomeSectionProps { + onEditModeChange: (isEditing: boolean) => void; +} + +const HomeSectionContent = ({ onEditModeChange }: HomeSectionProps) => { const [editStep, setEditStep] = useState(EDIT_STEP.VIEW); const [draft, setDraft] = useState({ reviews: EMPTY_REVIEWS, @@ -48,7 +52,7 @@ const HomeSectionContent = () => { const initialReviews = reviewsData ?? EMPTY_REVIEWS; const latestNews = data?.latestNews ?? EMPTY_NEWS; - const { control, getValues, setError, setValue, clearErrors } = + const { control, getValues, setError, setFocus, setValue, clearErrors } = useFormContext(); const homeHeaderImage = useWatch({ control, @@ -73,9 +77,14 @@ const HomeSectionContent = () => { }; const hasUnsavedChanges = - Boolean(homeHeaderImage?.file) || - !isSameOrder(initialReviews, draft.reviews) || - !isSameOrder(latestNews, draft.news); + isEditMode && + (Boolean(homeHeaderImage?.file) || + !isSameOrder(initialReviews, draft.reviews) || + !isSameOrder(latestNews, draft.news)); + + useEffect(() => { + onEditModeChange(isEditMode); + }, [isEditMode, onEditModeChange]); const validateHomeInputs = () => { const { homeHeaderImageFileName } = getValues(); @@ -85,6 +94,7 @@ const HomeSectionContent = () => { type: 'required', message: VALIDATION_CHECK.required.errorText, }); + setFocus('homeHeaderImageFileName'); return false; } @@ -162,11 +172,11 @@ const HomeSectionContent = () => { ); }; -const HomeSection = () => { +const HomeSection = (props: HomeSectionProps) => { return ( - + ); diff --git a/src/components/org/OrgAdmin/MyDropzone/index.tsx b/src/components/org/OrgAdmin/MyDropzone/index.tsx index 7709048c..22a1e621 100644 --- a/src/components/org/OrgAdmin/MyDropzone/index.tsx +++ b/src/components/org/OrgAdmin/MyDropzone/index.tsx @@ -1,6 +1,6 @@ 'use client'; -import { type MouseEvent, useCallback } from 'react'; +import { type MouseEvent, type MutableRefObject, useCallback } from 'react'; import { useDropzone } from 'react-dropzone'; import { type UseFormReturn, useWatch } from 'react-hook-form'; @@ -78,7 +78,7 @@ const MyDropzone = ({ e.preventDefault(); }; - const { getRootProps, getInputProps, isDragActive } = useDropzone({ + const { getRootProps, getInputProps, inputRef, isDragActive } = useDropzone({ onDrop, disabled, accept: { @@ -87,6 +87,27 @@ const MyDropzone = ({ 'image/png': [], }, }); + const { ref: formRef, ...formInputProps } = register(label, { + validate: (value) => { + if (!required) { + return true; + } + + if (value?.fileName || defaultPreviewUrl) { + return true; + } + + return VALIDATION_CHECK.required.errorText; + }, + }); + const dropzoneInputProps = getInputProps(); + const setInputRef = useCallback( + (element: HTMLInputElement | null) => { + formRef(element); + (inputRef as MutableRefObject).current = element; + }, + [formRef, inputRef], + ); return ( @@ -100,20 +121,9 @@ const MyDropzone = ({ isError={errorMsg} isDisabled={disabled}> { - if (!required) { - return true; - } - - if (value?.fileName || defaultPreviewUrl) { - return true; - } - - return VALIDATION_CHECK.required.errorText; - }, - })} - {...getInputProps()} + {...formInputProps} + {...dropzoneInputProps} + ref={setInputRef} disabled={disabled} /> {previewUrl ? ( diff --git a/src/components/org/OrgAdmin/RecruitSection/_components/Curriculum/index.tsx b/src/components/org/OrgAdmin/RecruitSection/_components/Curriculum/index.tsx index f048533f..e534d6d5 100644 --- a/src/components/org/OrgAdmin/RecruitSection/_components/Curriculum/index.tsx +++ b/src/components/org/OrgAdmin/RecruitSection/_components/Curriculum/index.tsx @@ -3,6 +3,7 @@ import { useFormContext } from 'react-hook-form'; import Modal from '@/components/org/OrgAdmin/common/Modal'; import useModal from '@/components/org/OrgAdmin/common/Modal/useModal'; +import { CURRICULUM_WEEK_COUNT } from '@/components/org/OrgAdmin/RecruitSection/_constants/constants'; import { PART_KO, PART_LIST, VALIDATION_CHECK } from '@/utils/org'; import { StInput, StTitle, StWrapper } from '../../../AboutSection/style'; @@ -17,7 +18,7 @@ import { StItem, StList, StWeek } from './style'; const CURRICULUM = PART_LIST.reduce( (acc, part) => { - acc[part] = Array.from({ length: 8 }); + acc[part] = Array.from({ length: CURRICULUM_WEEK_COUNT }); return acc; }, {} as Record, diff --git a/src/components/org/OrgAdmin/RecruitSection/_components/PartIntroduction/index.tsx b/src/components/org/OrgAdmin/RecruitSection/_components/PartIntroduction/index.tsx index 0e2a7002..50e1c6e0 100644 --- a/src/components/org/OrgAdmin/RecruitSection/_components/PartIntroduction/index.tsx +++ b/src/components/org/OrgAdmin/RecruitSection/_components/PartIntroduction/index.tsx @@ -185,6 +185,8 @@ const PartIntroSection = ({ }; const contentRegister = register(contentFieldName); + const oneLineRegister = register(oneLineFieldName); + const preferenceRegister = register(preferenceFieldName); return ( @@ -212,6 +214,7 @@ const PartIntroSection = ({