Skip to content
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
25 changes: 21 additions & 4 deletions src/features/event/ui/LinkInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { FunnelState } from '../model/FunnelContext';
import AddButton from '../../../../public/assets/event-manage/creation/AddBtn.svg';
import CloseButton from '../../../../public/assets/event-manage/creation/CloseBtn.svg';
Expand All @@ -14,9 +14,10 @@ interface LinkInputProps {
onChange?: (value: Link[]) => void;
eventState?: FunnelState['eventState'];
setEventState?: React.Dispatch<React.SetStateAction<FunnelState['eventState']>>;
onValidationChange?: (isValid: boolean) => void;
}

const LinkInput = ({ value, onChange, eventState, setEventState }: LinkInputProps) => {
const LinkInput = ({ value, onChange, eventState, setEventState, onValidationChange }: LinkInputProps) => {
const links = value ?? eventState?.referenceLinks ?? [];

const [activeInput, setActiveInput] = useState<{ field: 'title' | 'url' | null }>({
Expand All @@ -26,6 +27,11 @@ const LinkInput = ({ value, onChange, eventState, setEventState }: LinkInputProp
field: null,
});

const validateLinks = (linkArray: Link[]) => {
if (linkArray.length === 0) return true;
return linkArray.every(link => link.title.trim() !== '' && link.url.trim() !== '');
};

const updateAll = (newLinks: Link[]) => {
onChange?.(newLinks);
setEventState?.(prev => ({ ...prev, referenceLinks: newLinks }));
Expand All @@ -44,9 +50,20 @@ const LinkInput = ({ value, onChange, eventState, setEventState }: LinkInputProp
updateAll(newLinks);
};

useEffect(() => {
const isValid = validateLinks(links);
onValidationChange?.(isValid);
}, [links, onValidationChange]);

return (
<div className="flex flex-col gap-1">
<h1 className="font-bold text-black text-lg">관련 링크</h1>
<div className="flex flex-row gap-2 items-center">
<h1 className="font-bold text-black text-lg">관련 링크</h1>
{links.length > 0 && (<p className="text-placeholderText text-12">
링크 추가 시 하이퍼링크와 URL을 모두 입력해주세요
</p>)}

</div>

{links.map((link, index) => (
<div key={index} className="mb-2">
Expand All @@ -64,7 +81,7 @@ const LinkInput = ({ value, onChange, eventState, setEventState }: LinkInputProp
value={link.title}
onChange={e => updateLink(index, 'title', e.target.value)}
className="w-full min-w-[3rem] md:min-w-[6rem] h-8 text-placeholderText ml-1 outline-none bg-transparent text-sm md:text-base"
placeholder="참조링크"
placeholder="하이퍼링크"
autoFocus={activeInput.field === link.title && activeInput.field === 'title'}
/>
</div>
Expand Down
18 changes: 16 additions & 2 deletions src/pages/dashboard/ui/EventDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const EventDetailPage = () => {
const [bannerImageUrl, setBannerImageUrl] = useState('');
const [description, setDescription] = useState('');
const [referenceLinks, setReferenceLinks] = useState<Link[]>([]);
const [isLinkValid, setIsLinkValid] = useState(true);

const queryClient = useQueryClient();

Expand Down Expand Up @@ -67,16 +68,29 @@ const EventDetailPage = () => {
});
};

const handleLinkValidation = (valid: boolean) => {
setIsLinkValid(valid);
};

return (
<DashboardLayout centerContent="DASHBOARD">
<div className="flex flex-col gap-5 mt-8 px-7">
<h1 className="text-center text-xl font-bold mb-5">이벤트 상세 정보</h1>
<FileUpload value={bannerImageUrl} onChange={setBannerImageUrl} useDefaultImage={false} />
<TextEditor value={description} onChange={setDescription} />
<LinkInput value={referenceLinks} onChange={setReferenceLinks} />
<LinkInput
value={referenceLinks}
onChange={setReferenceLinks}
onValidationChange={handleLinkValidation}
/>
</div>
<div className="w-full p-7">
<Button label="저장하기" onClick={handleSave} className="w-full h-12 rounded-full" />
<Button
label="저장하기"
onClick={handleSave}
className="w-full h-12 rounded-full"
disabled={!isLinkValid}
/>
</div>
</DashboardLayout>
);
Expand Down
19 changes: 15 additions & 4 deletions src/pages/event/ui/create-event/EventInfoPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const EventInfoPage = ({ onValidationChange }: EventInfoPageProps) => {
const { eventState, setEventState } = useFunnelState();
const [isFileValid, setIsFileValid] = useState(false);
const [isTextValid, setIsTextValid] = useState(false);
const [isLinkValid, setIsLinkValid] = useState(true);

const handleFileValidation = (valid: boolean) => {
setIsFileValid(valid);
Expand All @@ -20,10 +21,15 @@ const EventInfoPage = ({ onValidationChange }: EventInfoPageProps) => {
const handleTextValidation = (valid: boolean) => {
setIsTextValid(valid);
};

const handleLinkValidation = (valid: boolean) => {
setIsLinkValid(valid);
};

useEffect(() => {
const allValid = isFileValid && isTextValid;
const allValid = isFileValid && isTextValid && isLinkValid;
onValidationChange?.(allValid);
}, [isFileValid, isTextValid, onValidationChange]);
}, [isFileValid, isTextValid, isLinkValid,onValidationChange]);

return (
<div className="w-full px-5 space-y-8">
Expand All @@ -34,13 +40,18 @@ const EventInfoPage = ({ onValidationChange }: EventInfoPageProps) => {
useDefaultImage={false}
onValidationChange={handleFileValidation}
/>
<TextEditor
<TextEditor
value={eventState?.description ?? ''}
eventState={eventState}
setEventState={setEventState}
onValidationChange={handleTextValidation}
/>
<LinkInput eventState={eventState} setEventState={setEventState} />
<LinkInput
eventState={eventState}
setEventState={setEventState}
onValidationChange={handleLinkValidation}
value={eventState?.referenceLinks}
/>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/shared/ui/backgrounds/EventRegisterLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const EventRegisterLayout = ({
<div className="absolute top-0 w-full h-36 md:h-40 bg-gradient-to-br from-[#FF5593] to-[rgb(255,117,119)] rounded-b-[60px] z-10">
<Header
centerContent="이벤트 등록"
leftButtonLabel={goHome ? ( <IconButton
leftButtonLabel={goHome ? (<IconButton
iconPath={<img src={HomeButton} />}
onClick={() => navigate('/')}
iconClassName="cursor-pointer z-30 ml-auto"
Expand Down