-
Notifications
You must be signed in to change notification settings - Fork 4
[Refactor] Observer pattern을 통한 전역 모달 관리 #155
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
Changes from 5 commits
7c54bb8
95e1f35
dbb16da
9a63791
5988b12
fac343c
da52f43
509a915
965750b
db00e1a
aae4be4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import { useEffect, useState, type ReactNode } from "react"; | ||
| import { useLocation } from "react-router-dom"; | ||
|
|
||
| import { modalStore } from "@/shared/model/store"; | ||
|
|
||
| import { Modal } from "../../shared/ui/modal/modal"; | ||
|
|
||
| interface ModalItem { | ||
| id: string; | ||
| content: ReactNode; | ||
| autoPlay?: number; | ||
| } | ||
hummingbbird marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| export const ModalProvider = () => { | ||
| const { pathname } = useLocation(); | ||
| const [modals, setModals] = useState<ModalItem[]>([]); | ||
|
|
||
| useEffect(() => { | ||
| modalStore.subscribe(setModals); | ||
| return () => modalStore.unsubscribe(); | ||
| }, []); | ||
|
Comment on lines
+16
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 외부 store 구독은 지금 패턴은 🤖 Prompt for AI Agents |
||
|
|
||
| useEffect(() => { | ||
| modalStore.reset(); | ||
| }, [pathname]); | ||
|
|
||
|
Comment on lines
+23
to
+26
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지금 reset 기준이
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지금 당장은 query를 통해 url이 바뀌는 페이지에서 모달이 사용되는 경우가 없어 |
||
| return ( | ||
| <> | ||
| {modals.map((modal) => { | ||
| return ( | ||
| <Modal | ||
| key={modal.id} | ||
| isOpen={true} | ||
| autoPlay={modal.autoPlay} | ||
| onClose={() => modalStore.close(modal.id)} | ||
| > | ||
| {modal.content} | ||
| </Modal> | ||
| ); | ||
| })} | ||
| </> | ||
| ); | ||
| }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 실제로 리팩토링된 부분을 보니 바로 이해가 되네요 !!! useModal 없이 모달을 관리할 수 있게 되면서, jsx 코드가 분리되고 별도의 선언 없이 store를 사용해 모달을 열 수 있는 점도 너무 좋습니다! 모달에 들어갈 내용들을 사용처에서 입력해주는 것도 응집도 측면에서 정말 좋은 거 같아요 천재 개발자 오수빈답습니다 👍👍
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,8 @@ | ||
| import { EXPERIENCE_TYPE } from "@/shared/config/experience"; | ||
| import { parseYMD } from "@/shared/lib/format-date"; | ||
| import { modalStore } from "@/shared/model/store"; | ||
| import { ModalBasic, Tooltip } from "@/shared/ui"; | ||
| import { Button } from "@/shared/ui/button/button"; | ||
| import { useModal } from "@/shared/ui/modal/use-modal"; | ||
| import { Tag } from "@/shared/ui/tag/tag"; | ||
| import { Textfield } from "@/shared/ui/textfield/textfield"; | ||
| import { HELP_TOOLTIP_CONTENT } from "@/shared/ui/tooltip/tooltip.content"; | ||
|
|
@@ -24,9 +24,6 @@ const ExperienceViewer = () => { | |
| const { showEditDelete, onClickEdit, onClickDelete, onToggleDefault } = | ||
| useExperienceHeaderActions(); | ||
|
|
||
| const { isOpen: isDeleteModalOpen, handleModal: toggleDeleteModal } = | ||
| useModal(); | ||
|
|
||
| const startDate = current?.startAt ? parseYMD(current.startAt) : null; | ||
| const endDate = current?.endAt ? parseYMD(current.endAt) : null; | ||
|
|
||
|
|
@@ -42,6 +39,22 @@ const ExperienceViewer = () => { | |
|
|
||
| const typeLabel = current.type ? EXPERIENCE_TYPE[current.type] : "미지정"; | ||
|
|
||
| const handleOpenDeleteModal = () => { | ||
| modalStore.open( | ||
| <ModalBasic | ||
| title="이 경험을 삭제하시겠습니까?" | ||
| subTitle="작성한 내용은 즉시 제거되며, 복구할 수 없습니다." | ||
| closeText="취소" | ||
| confirmText="삭제" | ||
| onClose={() => modalStore.reset()} // 취소 시 닫기 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 store는 store에서
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 말씀해주신대로 close(id)로 모달을 개별적으로 닫는 것이 안전한 방향이지만,
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 이해했습니다!! 말씀해주신 부분은 제가 추후 리팩토링 진행하면서 |
||
| onConfirm={() => { | ||
| onClickDelete(); // 실제 삭제 동작 | ||
| modalStore.reset(); // 모달 닫기 | ||
| }} | ||
| /> | ||
| ); | ||
|
Comment on lines
+42
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 확인창에서
🤖 Prompt for AI Agents |
||
| }; | ||
|
|
||
| return ( | ||
| <main className={s.page}> | ||
| <StickyHeader | ||
|
|
@@ -53,7 +66,7 @@ const ExperienceViewer = () => { | |
| <Button | ||
| variant="secondary" | ||
| size="small" | ||
| onClick={toggleDeleteModal} | ||
| onClick={handleOpenDeleteModal} | ||
| > | ||
| 삭제하기 | ||
| </Button> | ||
|
|
@@ -130,19 +143,6 @@ const ExperienceViewer = () => { | |
| </div> | ||
| </div> | ||
| </section> | ||
|
|
||
| <ModalBasic | ||
| title="이 경험을 삭제하시겠습니까?" | ||
| subTitle="작성한 내용은 즉시 제거되며, 복구할 수 없습니다." | ||
| closeText="취소" | ||
| confirmText="삭제" | ||
| isOpen={isDeleteModalOpen} | ||
| onClose={toggleDeleteModal} | ||
| onConfirm={() => { | ||
| toggleDeleteModal(); | ||
| onClickDelete(); | ||
| }} | ||
| /> | ||
| </main> | ||
| ); | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,8 +1,9 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useEffect, useRef, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useEffect, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useNavigate } from "react-router-dom"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ROUTES } from "@/app/routes/paths"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Button, Modal, useModal } from "@/shared/ui"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { modalStore } from "@/shared/model/store"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Button, Modal } from "@/shared/ui"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useGetExperience, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useGetCompanyList, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -19,53 +20,61 @@ export const SelectCompany = ({ onClick }: { onClick: () => void }) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const navigate = useNavigate(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data } = useGetExperience(); // 경험 조회 API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Report 전역 상태 */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // AI-Report 입력 단계 저장을 위한 전역 상태 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const setCompany = useReportStore((state) => state.setCompany); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const company = useReportStore((state) => state.company); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** 모달 상태 관리 */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { autoPlay, isOpen, handleModal } = useModal(3000); // 몇 초 뒤 닫히게 할 건지 정의 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const alertModal = useModal(); // 경험 등록 여부 확인 모달 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** 입력 데이터 상태 관리 */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 기업 입력 데이터 상태 관리 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [inputValue, setInputValue] = useState(""); // 실시간 입력 상태 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [searchKeyword, setSearchKeyword] = useState(""); // 디바운스된 키워드 상태 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [selectedCompany, setSelectedCompany] = useState<Company | null>( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| company | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data: searchResults = [] } = useGetCompanyList(searchKeyword); // 기업 검색 API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 경험 등록 여부 확인 모달 오픈 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 경험 등록 여부 확인 모달 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data?.totalElements === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!alertModal.isOpen) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| alertModal.openModal(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| modalStore.open( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+35
to
+39
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. data?.totalElements === 0일 때마다 바로 modalStore.open()을 호출하고 있어서, 쿼리 refetch가 일어나거나 컴포넌트가 다시 마운트되는 경우 동일한 안내 모달이 한 번 더 쌓일 수 있을 것 같아요 ! 이전에 open 여부를 한 번 체크해주는 흐름이 있었던 것 처럼 여기서도 고정 id를 넘겨서 중복 노출을 방지하는건 어떻게 생각하시나요 !? 👀
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 쿼리 refetch가 일어나는 경우는 다른 페이지에서 현재 페이지로 다시 포커스가 되거나( |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Content> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Title>아직 등록된 경험이 없습니다</Modal.Title> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.SubTitle>지금 바로 경험을 등록하러 가볼까요?</Modal.SubTitle> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal.Content> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Buttons> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button variant="secondary" onClick={() => navigate(ROUTES.HOME)}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 나가기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| variant="primary" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => navigate(ROUTES.EXPERIENCE_CREATE)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 이동하기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal.Buttons> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [data, alertModal]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [data, navigate]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // if (company?.id) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // const temp={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // id:company.id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // name:company.name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // setSelectedCompany(temp); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // }, [company]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data: searchResults = [] } = useGetCompanyList(searchKeyword); // 기업 검색 API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 모달 닫힘 여부 확인 후 페이지 이동 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const prevIsOpen = useRef(isOpen); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prevIsOpen.current === true && isOpen === false) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (selectedCompany) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setCompany(selectedCompany); // 선택된 기업 데이터 저장 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleSearch = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!selectedCompany) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 기업 선택 후, 대기하는 모달 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| modalStore.open( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Content type="auto"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Title>{selectedCompany.name}을 선택하셨습니다</Modal.Title> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.SubTitle>기업분석 내용을 불러오는 중입니다.</Modal.SubTitle> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal.Content> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Image /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3000, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setCompany(selectedCompany); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prevIsOpen.current = isOpen; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [isOpen, selectedCompany, onClick, setCompany]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+66
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 기업 선택 모달에도 고정 ID 사용을 권장해요.
🔧 제안 코드 modalStore.open(
<>
<Modal.Content type="auto">
<Modal.Title>
{josa(selectedCompany.name, "을/를")} 선택하셨습니다
</Modal.Title>
<Modal.SubTitle>기업분석 내용을 불러오는 중입니다.</Modal.SubTitle>
</Modal.Content>
<Modal.Image />
</>,
3000,
() => {
setCompany(selectedCompany);
onClick();
- }
+ },
+ "SELECT-COMPANY-LOADING"
);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+63
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 플로우는 재진입 방지가 필요합니다.
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className={styles.layout}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -77,39 +86,8 @@ export const SelectCompany = ({ onClick }: { onClick: () => void }) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onDebounceChange={setSearchKeyword} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| selectedItem={selectedCompany} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSelect={setSelectedCompany} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSearch={handleModal} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onSearch={handleSearch} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/** 경험 등록 여부 확인 모달 */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal isOpen={alertModal.isOpen} onClose={alertModal.closeModal}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Content> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Title>아직 등록된 경험이 없습니다</Modal.Title> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.SubTitle>지금 바로 경험을 등록하러 가볼까요?</Modal.SubTitle> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal.Content> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Buttons> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| variant="secondary" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size="large" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => navigate(ROUTES.HOME)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 나가기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| variant="primary" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size="large" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => navigate(ROUTES.EXPERIENCE_CREATE)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 이동하기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal.Buttons> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/** 기업 선택 후, 대기 모달 */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal autoPlay={autoPlay} isOpen={isOpen} onClose={handleModal}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Content type="auto"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Title>{selectedCompany?.name}을 선택하셨습니다</Modal.Title> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.SubTitle>기업분석 내용을 불러오는 중입니다.</Modal.SubTitle> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal.Content> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Modal.Image /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Modal> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Uh oh!
There was an error while loading. Please reload this page.