-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of https://github.com/MARU-EGG/MARU_EGG_FE
- Loading branch information
Showing
18 changed files
with
945 additions
and
79 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { useUserDetailTypeStore } from '../store/user-detail-type-store'; | ||
|
||
interface DetailTypeItem { | ||
middleName: string; | ||
lastNames: string[]; | ||
} | ||
|
||
export const useDetailTypePrompt = () => { | ||
const { detailTypeData } = useUserDetailTypeStore(); | ||
|
||
const itemMap = new Map<string, Set<string>>(); | ||
|
||
detailTypeData.forEach((item) => { | ||
const [middle, lastWithBracket] = item.name.split('('); | ||
const middleTrimmed = middle.trim(); | ||
const lastTrimmed = lastWithBracket ? lastWithBracket.replace(/\)$/, '').trim() : ''; | ||
|
||
if (!itemMap.has(middleTrimmed)) { | ||
itemMap.set(middleTrimmed, new Set<string>()); | ||
} | ||
|
||
if (lastTrimmed) { | ||
itemMap.get(middleTrimmed)?.add(lastTrimmed); | ||
} | ||
}); | ||
|
||
const itemList: DetailTypeItem[] = Array.from(itemMap.entries()).map(([middleName, lastNamesSet]) => ({ | ||
middleName, | ||
lastNames: Array.from(lastNamesSet), | ||
})); | ||
|
||
return { | ||
itemList, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { create } from 'zustand'; | ||
|
||
export interface AdmissionDetailTypeState { | ||
type?: 'SUSI' | 'PYEONIP' | 'JEONGSI'; | ||
id?: number; | ||
name?: string; | ||
} | ||
|
||
interface AdmissionDetailTypeStoreState { | ||
detailTypeData: AdmissionDetailTypeState[]; | ||
updateDetailTypeData: (data: AdmissionDetailTypeState[]) => void; | ||
deleteDetailType: (detailTypeId: number) => void; | ||
loading: boolean; | ||
setLoading: (load: boolean) => void; | ||
} | ||
|
||
const useAdmissionDetailTypeStore = create<AdmissionDetailTypeStoreState>((set) => ({ | ||
detailTypeData: [], | ||
updateDetailTypeData: (data) => set({ detailTypeData: data }), | ||
deleteDetailType: (id) => | ||
set((state) => ({ | ||
detailTypeData: state.detailTypeData.filter((data) => data.id !== id), | ||
})), | ||
loading: false, | ||
setLoading: (load) => set({ loading: load }), | ||
})); | ||
|
||
export default useAdmissionDetailTypeStore; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { create } from 'zustand'; | ||
export interface DetailTypeItem { | ||
middleName: string; | ||
lastNames: string[]; | ||
} | ||
|
||
//TSK-53 admission-detail-type-store.ts와 일부 겹침 나중에 병합 필요성 | ||
export interface UserDetailTypeState { | ||
type: 'SUSI' | 'JEONGSI' | 'PYEONIP'; | ||
id: number; | ||
name: string; | ||
} | ||
|
||
interface UserDetailTypeStoreState { | ||
detailTypeData: UserDetailTypeState[]; | ||
updateDetailTypeData: (data: UserDetailTypeState[]) => void; | ||
loading: boolean; | ||
selectedName: string; | ||
setSelectedName: (name: string) => void; | ||
setLoading: (load: boolean) => void; | ||
itemsArray: DetailTypeItem[]; | ||
setItemArray: (dataArray: DetailTypeItem[]) => void; | ||
} | ||
|
||
export const useUserDetailTypeStore = create<UserDetailTypeStoreState>((set) => ({ | ||
detailTypeData: [], | ||
loading: false, | ||
itemsArray: [], | ||
selectedName: '', | ||
setSelectedName: (name) => set({ selectedName: name }), | ||
updateDetailTypeData: (data) => set({ detailTypeData: data }), | ||
setLoading: (load) => set({ loading: load }), | ||
setItemArray: (data) => set({ itemsArray: data }), | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React from 'react'; | ||
import { Meta, StoryFn } from '@storybook/react'; | ||
import Dropdown from './dropdown'; | ||
|
||
export default { | ||
title: 'Components/Dropdown', | ||
component: Dropdown, | ||
argTypes: { | ||
type: { | ||
control: { type: 'select' }, | ||
options: ['SUSI', 'JEONGSI', 'PYEONIP'], | ||
}, | ||
}, | ||
} as Meta<typeof Dropdown>; | ||
|
||
const Template: StoryFn<typeof Dropdown> = (args) => <Dropdown {...args} />; | ||
|
||
export const SUSI = Template.bind({}); | ||
SUSI.args = { | ||
type: 'SUSI', | ||
items: [ | ||
{ | ||
middleName: '학생부교과', | ||
lastNames: ['학교장추천', '교과면접', '기회균형', '특성화고교', '만학도', '특성화고등졸재직자', '특수교육대상자'], | ||
}, | ||
{ | ||
middleName: '학생부종합', | ||
lastNames: ['명지인재면접', '명지인재서류', '크리스천리더', '사회적배려대상자', '농어촌학생'], | ||
}, | ||
{ | ||
middleName: '실기/실적', | ||
lastNames: ['실기우수자', '특기자-문학/체육'], | ||
}, | ||
], | ||
}; | ||
|
||
export const JEONGSI = Template.bind({}); | ||
JEONGSI.args = { | ||
type: 'JEONGSI', | ||
items: [ | ||
{ | ||
middleName: '수능', | ||
lastNames: ['일반-가/나/다', '실기-가/나/다', '농어촌학생', '특성화고교'], | ||
}, | ||
{ | ||
middleName: '실기/실적', | ||
lastNames: ['실기우수자'], | ||
}, | ||
{ | ||
middleName: '학생부교과', | ||
lastNames: ['만학도', '특성화고등졸재직자'], | ||
}, | ||
], | ||
}; | ||
|
||
export const PYEONIP = Template.bind({}); | ||
PYEONIP.args = { | ||
type: 'PYEONIP', | ||
items: [ | ||
{ middleName: '일반', lastNames: [] }, | ||
{ middleName: '학사', lastNames: [] }, | ||
{ middleName: '농어촌학생', lastNames: [] }, | ||
{ middleName: '특성화고교', lastNames: [] }, | ||
{ middleName: '재외국민', lastNames: [] }, | ||
{ middleName: '특성화고등졸재직자', lastNames: [] }, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import React from 'react'; | ||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; | ||
import { ChevronRightIcon } from '@radix-ui/react-icons'; | ||
import { useDetailTypePrompt } from '../../../../hooks/use-detail-type-prompt.hooks'; | ||
import { useUserDetailTypeStore } from '../../../../store/user-detail-type-store'; | ||
import usePresetButton from '../../../../hooks/use-preset-button.hooks'; | ||
|
||
interface DropdownProps { | ||
type: 'SUSI' | 'JEONGSI' | 'PYEONIP'; | ||
items: { middleName: string; lastNames: string[] }[]; | ||
} | ||
|
||
const Dropdown: React.FC<DropdownProps> = ({ type }) => { | ||
const { itemList: items } = useDetailTypePrompt(); | ||
const { setSelectedName } = useUserDetailTypeStore(); | ||
const { handleDetailTypeButtonClick } = usePresetButton(); | ||
|
||
const handleNameClick = (name: string) => { | ||
setSelectedName(name); | ||
handleDetailTypeButtonClick(name); | ||
}; | ||
|
||
return ( | ||
<DropdownMenu.Root open> | ||
<DropdownMenu.Trigger asChild> | ||
<button style={{ display: 'hidden' }}></button> | ||
</DropdownMenu.Trigger> | ||
<DropdownMenu.Portal> | ||
<DropdownMenu.Content className="rounded-md border-gray-300 bg-white" align="start"> | ||
{type === 'PYEONIP' | ||
? // 편입의 경우, 한 번에 전체 목록 표시 | ||
items.map((item, index) => ( | ||
<DropdownMenu.Item | ||
key={index} | ||
className="cursor-pointer px-4 py-2 hover:bg-gray-100" | ||
onClick={() => handleNameClick(item.middleName)} | ||
> | ||
{item.middleName} | ||
</DropdownMenu.Item> | ||
)) | ||
: // 수시, 정시의 경우, 중간 이름을 상위 메뉴로, 마지막 이름을 하위 메뉴로 표시 | ||
items.map((item, index) => ( | ||
<DropdownMenu.Sub key={index}> | ||
<DropdownMenu.SubTrigger className="flex cursor-pointer items-center justify-between px-4 py-2 hover:bg-gray-100"> | ||
{item.middleName} | ||
<ChevronRightIcon /> | ||
</DropdownMenu.SubTrigger> | ||
<DropdownMenu.Portal> | ||
<DropdownMenu.SubContent className="rounded-md border border-gray-300 bg-white shadow-lg"> | ||
{item.lastNames.map((lastName, subIndex) => ( | ||
<DropdownMenu.Item | ||
key={subIndex} | ||
className="cursor-pointer px-4 py-2 hover:bg-gray-100" | ||
onClick={() => handleNameClick(lastName)} | ||
> | ||
{lastName} | ||
</DropdownMenu.Item> | ||
))} | ||
</DropdownMenu.SubContent> | ||
</DropdownMenu.Portal> | ||
</DropdownMenu.Sub> | ||
))} | ||
</DropdownMenu.Content> | ||
</DropdownMenu.Portal> | ||
</DropdownMenu.Root> | ||
); | ||
}; | ||
|
||
export default Dropdown; |
Oops, something went wrong.