✨ frontend add
This commit is contained in:
67
frontend/portal/src/stores/condition.ts
Normal file
67
frontend/portal/src/stores/condition.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { atom, atomFamily, DefaultValue, selectorFamily } from 'recoil'
|
||||
|
||||
/**
|
||||
* 조회조건 상태관리
|
||||
* key를 기준으로 메뉴별로 사용
|
||||
*/
|
||||
|
||||
export type conditionValue = { [key: string]: string | number }
|
||||
|
||||
export const conditionAtom = atomFamily<conditionValue, string>({
|
||||
key: 'conditionAtom',
|
||||
default: undefined,
|
||||
})
|
||||
|
||||
export const fieldIdsAtom = atom<string[]>({
|
||||
key: 'fieldIdsAtom',
|
||||
default: [],
|
||||
})
|
||||
|
||||
export const conditionSelector = selectorFamily<conditionValue, string>({
|
||||
key: 'conditionSelector',
|
||||
get:
|
||||
id =>
|
||||
({ get }) =>
|
||||
get(conditionAtom(id)),
|
||||
set:
|
||||
id =>
|
||||
({ set, get }, newValue) => {
|
||||
set(conditionAtom(id), newValue)
|
||||
const ids = get(fieldIdsAtom)
|
||||
if (!ids.includes(id)) {
|
||||
set(fieldIdsAtom, prev => [...prev, id])
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const conditionStateSelector = selectorFamily<
|
||||
Record<string, conditionValue>,
|
||||
string[]
|
||||
>({
|
||||
key: 'conditionStateSelector',
|
||||
get:
|
||||
ids =>
|
||||
({ get }) => {
|
||||
return ids.reduce<Record<string, conditionValue>>((result, id) => {
|
||||
const value = get(conditionAtom(id))
|
||||
return {
|
||||
...result,
|
||||
[id]: value,
|
||||
}
|
||||
}, {})
|
||||
},
|
||||
set:
|
||||
ids =>
|
||||
({ get, set, reset }, newValue) => {
|
||||
if (newValue instanceof DefaultValue) {
|
||||
reset(fieldIdsAtom)
|
||||
const ids = get(fieldIdsAtom)
|
||||
ids.forEach(id => reset(conditionAtom(id)))
|
||||
} else {
|
||||
set(fieldIdsAtom, Object.keys(newValue))
|
||||
ids.forEach(id => {
|
||||
set(conditionAtom(id), newValue[id])
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
57
frontend/portal/src/stores/error.ts
Normal file
57
frontend/portal/src/stores/error.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { DEFAULT_ERROR_MESSAGE } from '@constants'
|
||||
import { AxiosError } from 'axios'
|
||||
import { atom, DefaultValue, selector } from 'recoil'
|
||||
|
||||
/**
|
||||
* Global error 상태관리
|
||||
*/
|
||||
|
||||
interface IErrors {
|
||||
defaultMessage: string
|
||||
field: string
|
||||
rejectedValue?: string
|
||||
}
|
||||
|
||||
export interface IErrorProps {
|
||||
open?: boolean
|
||||
error?: AxiosError
|
||||
status?: number
|
||||
message?: string
|
||||
errors?: IErrors[]
|
||||
}
|
||||
|
||||
export const errorStateAtom = atom<IErrorProps>({
|
||||
key: 'errorStateAtom',
|
||||
default: { error: null } as IErrorProps,
|
||||
})
|
||||
|
||||
export const errorStateSelector = selector<IErrorProps>({
|
||||
key: 'errorStateSelector',
|
||||
get: ({ get }) => {
|
||||
return get(errorStateAtom)
|
||||
},
|
||||
set: ({ set, reset }, newValue) => {
|
||||
if (newValue instanceof DefaultValue) {
|
||||
reset(errorStateAtom)
|
||||
} else {
|
||||
const error = newValue.error
|
||||
let message = error?.message || newValue.message || DEFAULT_ERROR_MESSAGE
|
||||
let errors: IErrors[] = []
|
||||
let status = newValue.status || 500
|
||||
if (error?.response) {
|
||||
message = error.response.data.message || message
|
||||
|
||||
errors = error.response.data.errors
|
||||
status = error.response.status
|
||||
}
|
||||
|
||||
set(errorStateAtom, {
|
||||
open: true,
|
||||
error,
|
||||
status,
|
||||
message,
|
||||
errors,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
5
frontend/portal/src/stores/index.ts
Normal file
5
frontend/portal/src/stores/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './condition'
|
||||
export * from './error'
|
||||
export * from './menus'
|
||||
export * from './page'
|
||||
export * from './user'
|
||||
64
frontend/portal/src/stores/menus.ts
Normal file
64
frontend/portal/src/stores/menus.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { atom, selector } from 'recoil'
|
||||
|
||||
export interface ISideMenu {
|
||||
children: ISideMenu[]
|
||||
engName: string
|
||||
icon: string
|
||||
id: number
|
||||
isChecked: boolean
|
||||
korName: string
|
||||
level: number
|
||||
menuRoleId: number
|
||||
parentId: number
|
||||
roleId: string
|
||||
sortSeq: number
|
||||
urlPath: string
|
||||
expanded: boolean
|
||||
isShow: boolean
|
||||
menuType: string
|
||||
}
|
||||
|
||||
export const menuStateAtom = atom({
|
||||
key: 'menuStateAtom',
|
||||
default: [] as ISideMenu[],
|
||||
})
|
||||
|
||||
export const currentMenuStateAtom = atom({
|
||||
key: 'currentMenuStateAtom',
|
||||
default: {} as ISideMenu,
|
||||
})
|
||||
|
||||
export const flatMenusSelect = selector<ISideMenu[]>({
|
||||
key: 'flatMenusSelect',
|
||||
get: ({ get }) => {
|
||||
const menus = get(menuStateAtom)
|
||||
|
||||
let flatMenus = []
|
||||
const getAllItems = (menu: ISideMenu) => {
|
||||
flatMenus.push(menu)
|
||||
if (menu.children) {
|
||||
return menu.children.map(i => getAllItems(i))
|
||||
}
|
||||
}
|
||||
|
||||
menus.forEach(item => {
|
||||
getAllItems(item)
|
||||
})
|
||||
|
||||
return flatMenus
|
||||
},
|
||||
})
|
||||
|
||||
export const sideMenuSelect = selector<ISideMenu[]>({
|
||||
key: 'sideMenuSelect',
|
||||
get: ({ get }) => {
|
||||
const current = get(currentMenuStateAtom)
|
||||
const flatMenus = get(flatMenusSelect)
|
||||
if (!current.parentId) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const parent = flatMenus.find(item => item.id === current.parentId)
|
||||
return parent.children
|
||||
},
|
||||
})
|
||||
61
frontend/portal/src/stores/page.ts
Normal file
61
frontend/portal/src/stores/page.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { atomFamily, DefaultValue, selectorFamily } from 'recoil'
|
||||
import { fieldIdsAtom } from './condition'
|
||||
|
||||
/**
|
||||
* page 상태관리
|
||||
* key를 기준으로 메뉴별로 사용
|
||||
*/
|
||||
|
||||
export const pageAtom = atomFamily<number, string>({
|
||||
key: 'pageAtom',
|
||||
default: undefined,
|
||||
})
|
||||
|
||||
export const pageSelector = selectorFamily<number, string>({
|
||||
key: 'pageSelector',
|
||||
get:
|
||||
id =>
|
||||
({ get }) =>
|
||||
get(pageAtom(id)),
|
||||
set:
|
||||
id =>
|
||||
({ set, get }, newValue) => {
|
||||
set(pageAtom(id), newValue)
|
||||
const ids = get(fieldIdsAtom)
|
||||
if (!ids.includes(id)) {
|
||||
set(fieldIdsAtom, prev => [...prev, id])
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const pageStateSelector = selectorFamily<
|
||||
Record<string, number>,
|
||||
string[]
|
||||
>({
|
||||
key: 'pageStateSelector',
|
||||
get:
|
||||
ids =>
|
||||
({ get }) => {
|
||||
return ids.reduce<Record<string, number>>((result, id) => {
|
||||
const value = get(pageAtom(id))
|
||||
return {
|
||||
...result,
|
||||
[id]: value,
|
||||
}
|
||||
}, {})
|
||||
},
|
||||
set:
|
||||
ids =>
|
||||
({ get, set, reset }, newValue) => {
|
||||
if (newValue instanceof DefaultValue) {
|
||||
reset(fieldIdsAtom)
|
||||
const ids = get(fieldIdsAtom)
|
||||
ids.forEach(id => reset(pageAtom(id)))
|
||||
} else {
|
||||
set(fieldIdsAtom, Object.keys(newValue))
|
||||
ids.forEach(id => {
|
||||
set(pageAtom(id), newValue[id])
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
18
frontend/portal/src/stores/user.ts
Normal file
18
frontend/portal/src/stores/user.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { atom } from 'recoil'
|
||||
|
||||
export interface IUser {
|
||||
email: string
|
||||
userId: string
|
||||
userName: string
|
||||
googleId?: string
|
||||
kakaoId?: string
|
||||
naverId?: string
|
||||
isSocialUser: boolean
|
||||
hasPassword: boolean
|
||||
verification?: any
|
||||
}
|
||||
|
||||
export const userAtom = atom<IUser>({
|
||||
key: 'userAtom',
|
||||
default: null,
|
||||
})
|
||||
Reference in New Issue
Block a user