frontend add

This commit is contained in:
shinmj
2021-10-21 09:03:17 +09:00
parent 8caa4bbc5a
commit cb9d50511e
443 changed files with 88282 additions and 0 deletions

View File

@@ -0,0 +1,268 @@
import {
GoogleLoginButton,
KakaoLoginButton,
NaverLoginButton,
} from '@components/Buttons'
import CustomAlert, { CustomAlertPrpps } from '@components/CustomAlert'
import { PasswordConfirm } from '@components/Password'
import { IUserForm, UserInfoDone, UserInfoModified } from '@components/UserInfo'
import { userService } from '@service'
import { errorStateSelector, userAtom } from '@stores'
import produce from 'immer'
import { useRouter } from 'next/router'
import React, { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
import { useRecoilValue, useSetRecoilState } from 'recoil'
interface AlertProps extends CustomAlertPrpps {
message: string
}
const UserInfo = () => {
const router = useRouter()
const { t } = useTranslation()
const user = useRecoilValue(userAtom)
const setUser = useSetRecoilState(userAtom)
const setErrorState = useSetRecoilState(errorStateSelector)
const [checkedEmail, setCheckedEmail] = useState<boolean>(false)
const [modified, setModified] = useState<boolean>(false)
const [customAlert, setCustomAlert] = useState<AlertProps | undefined>({
open: false,
message: '',
handleAlert: () => {},
})
// form hook
const methods = useForm<IUserForm>({
defaultValues: {
password: '',
email: user?.email || '',
userName: user?.userName || '',
},
})
const { control, handleSubmit, formState, getValues, setFocus } = methods
useEffect(() => {
if (user && user.verification) {
setUser({
...user,
verification: null,
})
}
}, [])
// 비밀번호 확인
const handleCheckPassword = async (data: IUserForm) => {
data = produce(data, draft => {
draft.password = data.currentPassword
})
try {
const result = await userService.matchPassword(data.currentPassword)
if (result === true) {
setUser({
...user,
verification: {
provider: 'password',
password: data.currentPassword,
},
})
} else {
throw new Error(t('err.user.password.notmatch'))
}
} catch (error) {
setErrorState({ error })
}
}
const showMessage = (message: string, callback?: () => void) => {
setCustomAlert({
open: true,
message,
handleAlert: () => {
setCustomAlert({
...customAlert,
open: false,
})
if (callback) callback()
},
})
}
// 변경
const handleUpdate = async (data: IUserForm) => {
if (user.email === data.email && user.userName === data.userName) {
showMessage(t('msg.notmodified'))
return
}
if (user.email !== data.email && !checkedEmail) {
showMessage(t('msg.user.email.check'), () => {
setFocus('email')
})
return
}
try {
const result = await userService.updateInfo(user.userId, {
...data,
...user.verification,
})
if (result) {
setUser({
...user,
...data,
})
setModified(true)
} else {
throw new Error(t('err.internal.server'))
}
} catch (error) {
setErrorState({ error })
}
}
// 메인 이동
const handleFirst = () => {
setUser({
...user,
verification: null,
})
router.push('/')
}
// 카카오 로그인
const handleKakaoLogin = async response => {
if (response.profile?.id?.toString() === user.kakaoId) {
// setVerification({
// provider: 'kakao',
// token: response.response.access_token,
// })
setUser({
...user,
verification: {
provider: 'kakao',
token: response.response.access_token,
},
})
setErrorState(null)
} else {
setErrorState(t('err.user.login.social'))
}
}
// 네이버 로그인
const handleNaverLogin = async response => {
if (response.user?.id === user.naverId) {
// Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
// 로그인 페이지에서는 잘되는데 이유를 모르겠다. 구글/카카오는 잘된다. 편법으로 일단 진행
/* setVerification({
provider: 'naver',
token: response.accessToken,
}) */
setUser({
...user,
verification: {
provider: 'naver',
token: response.accessToken,
},
})
setErrorState(null)
} else {
setErrorState(t('err.user.login.social'))
}
}
// 구글 로그인
const handleGoogleLogin = async response => {
if (response.googleId === user.googleId) {
// setVerification({
// provider: 'google',
// token: response.tokenId,
// })
setUser({
...user,
verification: {
provider: 'google',
token: response.tokenId,
},
})
setErrorState(null)
} else {
setErrorState(t('err.user.login.social'))
}
}
// 비밀번호 랜더링
const renderPasswordForm = () => {
return (
<article className="mypage">
<div className="message small">
<span className="">{t('label.text.required.login')}</span>
</div>
{user?.hasPassword === true && (
<PasswordConfirm
control={control}
formState={formState}
handleCheckPassword={handleSubmit(handleCheckPassword)}
handleList={handleFirst}
/>
)}
{user?.isSocialUser === true && (
<>
<h3>
<span>{t('label.title.oauth')}</span>
</h3>
<div className="btn_social">
{user?.kakaoId && (
<KakaoLoginButton handleClick={handleKakaoLogin} />
)}
{user?.naverId && (
<NaverLoginButton handleClick={handleNaverLogin} />
)}
{user?.googleId && (
<GoogleLoginButton handleClick={handleGoogleLogin} />
)}
</div>
</>
)}
</article>
)
}
return (
<>
{modified === false && (
<form>
{!user?.verification && renderPasswordForm()}
{user?.verification && (
<UserInfoModified
control={control}
formState={formState}
handleUpdate={handleSubmit(handleUpdate)}
handleList={handleFirst}
getValues={getValues}
setFocus={setFocus}
showMessage={showMessage}
setCheckedEmail={setCheckedEmail}
/>
)}
</form>
)}
{modified === true && <UserInfoDone handleList={handleFirst} />}
<CustomAlert
contentText={customAlert.message}
open={customAlert.open}
handleAlert={customAlert.handleAlert}
/>
</>
)
}
export default UserInfo

View File

@@ -0,0 +1,50 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useRouter } from 'next/router'
import { makeStyles, Theme } from '@material-ui/core/styles'
const useStyles = makeStyles((theme: Theme) => ({
mg0: {
margin: '0 auto',
},
}))
const Bye = () => {
const router = useRouter()
const classes = useStyles()
const { t } = useTranslation()
const handleMain = event => {
event.preventDefault()
router.push('/')
}
return (
<section className={classes.mg0}>
<article className="rocation">
<h2>{t('label.title.mypage')}</h2>
<ul>
<li>{t('label.title.home')}</li>
<li>{t('label.title.mypage')}</li>
<li>{t('label.title.leave')}</li>
</ul>
</article>
<article className="mypage">
<div className="message">
<span className="end">
{t('label.text.leave.complete1')}
<br />
{t('label.text.leave.complete2')}
</span>
</div>
<div className="btn_center">
<a href="#" onClick={handleMain}>
{t('label.button.first')}
</a>
</div>
</article>
</section>
)
}
export default Bye

View File

@@ -0,0 +1,202 @@
import {
GoogleLoginButton,
KakaoLoginButton,
NaverLoginButton,
} from '@components/Buttons'
import CustomConfirm, { CustomConfirmPrpps } from '@components/CustomConfirm'
import { PasswordConfirm } from '@components/Password'
import { IVerification, userService } from '@service'
import { errorStateSelector, userAtom } from '@stores'
import { useRouter } from 'next/router'
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
import { useRecoilValue, useSetRecoilState } from 'recoil'
interface IUserForm {
currentPassword: string
}
interface AlertProps extends CustomConfirmPrpps {
message: string
}
const UserLeave = () => {
const router = useRouter()
const { t } = useTranslation()
const user = useRecoilValue(userAtom)
const [customConfirm, setCustomConfirm] = useState<AlertProps | null>(null)
const setErrorState = useSetRecoilState(errorStateSelector)
// form hook
const methods = useForm<IUserForm>({
defaultValues: {
currentPassword: '',
},
})
const { control, handleSubmit, formState } = methods
// 탈퇴 처리
const leave = async (data: IVerification) => {
console.log('leave', data)
try {
const result = await userService.leave(data)
if (result === true) {
router.push('/auth/logout?redirect=/user/leave/bye')
} else {
throw new Error(t('err.internal.server'))
}
} catch (error) {
setErrorState({ error })
}
}
const leaveConfirm = (data: IVerification) => {
setCustomConfirm({
open: true,
message: t('msg.confirm.leave'),
handleConfirm: () => {
setCustomConfirm({
...customConfirm,
open: false,
})
leave(data)
},
handleCancel: () => {
setCustomConfirm({ ...customConfirm, open: false })
},
})
}
// 탈퇴 클릭
const handleLeave = async (data: IUserForm) => {
const { currentPassword } = data
try {
const result = await userService.matchPassword(currentPassword)
if (result === true) {
leaveConfirm({
provider: 'password',
password: currentPassword,
})
} else {
throw new Error(t('err.user.password.notmatch'))
}
} catch (error) {
setErrorState({ error })
}
}
// 카카오 로그인
const handleKakaoLogin = async response => {
if (response.response?.access_token) {
await leave({
provider: 'kakao',
token: response.response.access_token,
})
} else {
setErrorState({ message: t('err.user.login.social') })
}
}
// 네이버 로그인
const handleNaverLogin = async response => {
if (response.accessToken) {
await leave({
provider: 'naver',
token: response.accessToken,
})
} else {
setErrorState({ message: t('err.user.login.social') })
}
}
// 구글 로그인
const handleGoogleLogin = async response => {
if (response.tokenId) {
await leave({
provider: 'google',
token: response.tokenId,
})
} else {
setErrorState({ message: t('err.user.login.social') })
}
}
const handleList = () => {
router.push('/')
}
return (
<>
<form>
<article className="mypage">
<p>
{t('label.text.user.leave1')}
<br />
{t('label.text.user.leave2')}
</p>
<div className="guide">
<h4>{t('label.title.guide')}</h4>
<ul>
<li>{t('label.text.user.leave.guide1')}</li>
<li>{t('label.text.user.leave.guide2')}</li>
<li>{t('label.text.user.leave.guide3')}</li>
</ul>
</div>
{user?.hasPassword === true && (
<>
<p>{t('label.text.user.leave.password')}</p>
<PasswordConfirm
control={control}
formState={formState}
handleCheckPassword={handleSubmit(handleLeave)}
handleList={handleList}
/>
</>
)}
{user?.isSocialUser === true && (
<>
<h3>
<span>{t('label.title.oauth')}</span>
</h3>
<div className="btn_social">
{user?.kakaoId && (
<KakaoLoginButton
handleClick={handleKakaoLogin}
confirmMessage={t('msg.confirm.leave')}
/>
)}
{user?.naverId && (
<NaverLoginButton
handleClick={handleNaverLogin}
confirmMessage={t('msg.confirm.leave')}
/>
)}
{user?.googleId && (
<GoogleLoginButton
handleClick={handleGoogleLogin}
confirmMessage={t('msg.confirm.leave')}
/>
)}
</div>
</>
)}
</article>
{customConfirm && (
<CustomConfirm
handleConfirm={customConfirm.handleConfirm}
handleCancel={customConfirm.handleCancel}
contentText={customConfirm.message}
open={customConfirm.open}
/>
)}
</form>
</>
)
}
export default UserLeave

View File

@@ -0,0 +1,216 @@
import {
GoogleLoginButton,
KakaoLoginButton,
NaverLoginButton,
} from '@components/Buttons'
import {
IUserPasswordForm,
PasswordChange,
PasswordConfirm,
PasswordDone,
} from '@components/Password'
import { userService } from '@service'
import { errorStateSelector, userAtom } from '@stores'
import { useRouter } from 'next/router'
import React, { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
import { useRecoilValue, useSetRecoilState } from 'recoil'
const EditPassword = () => {
const router = useRouter()
const { t } = useTranslation()
const user = useRecoilValue(userAtom)
const setUser = useSetRecoilState(userAtom)
const setErrorState = useSetRecoilState(errorStateSelector)
const [modified, setModified] = useState<boolean>(false)
// form hook
const methods = useForm<IUserPasswordForm>({
defaultValues: {
currentPassword: '',
newPassword: '',
newPasswordConfirm: '',
},
})
const { control, handleSubmit, formState, setFocus } = methods
useEffect(() => {
if (user && user.verification) {
setUser({
...user,
verification: null,
})
}
}, [])
// 메인 이동
const handleFirst = () => {
setUser({
...user,
verification: null,
})
router.push('/')
}
// 비밀번호 확인
const handleCheckPassword = async (data: IUserPasswordForm) => {
try {
const result = await userService.matchPassword(data.currentPassword)
if (result === true) {
setUser({
...user,
verification: {
provider: 'password',
password: data.currentPassword,
},
})
} else {
throw new Error(t('err.user.password.notmatch'))
}
} catch (error) {
setErrorState({ error })
}
}
// 비밀번호 변경
const handleChangePassword = async (data: IUserPasswordForm) => {
try {
const result = await userService.updatePassword({
...user.verification,
newPassword: data.newPassword,
})
if (result === true) {
setModified(true)
} else {
throw new Error(t('err.internal.server'))
}
} catch (error) {
setErrorState({ error })
}
}
// 카카오 로그인
const handleKakaoLogin = response => {
if (response.profile?.id?.toString() === user.kakaoId) {
// setVerification({
// provider: 'kakao',
// token: response.response.access_token,
// })
setUser({
...user,
verification: {
provider: 'kakao',
token: response.response.access_token,
},
})
} else {
setErrorState({ message: t('err.user.social.notmatch') })
}
}
// 네이버 로그인
const handleNaverLogin = async response => {
if (response.user?.id === user.naverId) {
// Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
// 로그인 페이지에서는 잘되는데 이유를 모르겠다. 구글/카카오는 잘된다. 편법으로 일단 진행
/* setVerification({
provider: 'naver',
token: response.accessToken,
}) */
setUser({
...user,
verification: {
provider: 'naver',
token: response.accessToken,
},
})
} else {
setErrorState({ message: t('err.user.social.notmatch') })
}
}
// 구글 로그인
const handleGoogleLogin = response => {
if (response.googleId === user.googleId) {
// setVerification({
// provider: 'google',
// token: response.tokenId,
// })
setUser({
...user,
verification: {
provider: 'google',
token: response.tokenId,
},
})
} else {
setErrorState({ message: t('err.user.social.notmatch') })
}
}
// 비밀번호 랜더링
const renderPasswordForm = () => {
return (
<article className="mypage">
<div className="message small">
<span className="">{t('label.text.required.login')}</span>
</div>
{user?.hasPassword === true && (
<PasswordConfirm
control={control}
formState={formState}
handleCheckPassword={handleSubmit(handleCheckPassword)}
handleList={handleFirst}
/>
)}
{user?.isSocialUser === true && (
<>
<h3>
<span>{t('label.title.oauth')}</span>
</h3>
<div className="btn_social">
{user?.kakaoId && (
<KakaoLoginButton handleClick={handleKakaoLogin} />
)}
{user?.naverId && (
<NaverLoginButton handleClick={handleNaverLogin} />
)}
{user?.googleId && (
<GoogleLoginButton handleClick={handleGoogleLogin} />
)}
</div>
</>
)}
</article>
)
}
return (
<>
{modified === false && (
<form>
{!user?.verification && renderPasswordForm()}
{user?.verification && (
<PasswordChange
control={control}
formState={formState}
handleChangePassword={handleSubmit(handleChangePassword)}
setFocus={setFocus}
currentPassword={user.verification.password}
handleList={handleFirst}
/>
)}
</form>
)}
{modified === true && <PasswordDone handleList={handleFirst} />}
</>
)
}
export default EditPassword

View File

@@ -0,0 +1,98 @@
import { BottomButtons, IButtons } from '@components/Buttons'
import { ReserveInfo, ReserveItemInfo } from '@components/Reserve'
import { ICode, IReserve, reserveService } from '@service'
import { GetServerSideProps } from 'next'
import { useRouter } from 'next/router'
import React, { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
interface UserReserveDetailProps {
initData: IReserve
status?: ICode
}
const UserReserveDetail = ({ initData, status }: UserReserveDetailProps) => {
const router = useRouter()
const { t } = useTranslation()
// 버튼
const bottomButtons = useMemo((): IButtons[] => {
const buttons: IButtons[] = [
{
id: 'item-list-button',
title: t('label.button.list'),
href: `/user/reserve`,
},
]
if (
initData?.reserveStatusId === 'approve' ||
initData?.reserveStatusId === 'request'
) {
buttons.push({
id: 'item-cancel-button',
title: `${t('reserve')} ${t('label.button.cancel')}`,
href: `/user/reserve/cancel/${initData.reserveId}`,
className: 'blue',
})
return buttons.reverse()
}
return buttons
}, [t, router.query, initData])
return (
<>
<div className="table_view02">
{initData && (
<>
<ReserveItemInfo
data={initData.reserveItem}
reserveStatus={status}
/>
<ReserveInfo data={initData} />
</>
)}
<BottomButtons handleButtons={bottomButtons} />
</div>
</>
)
}
export const getServerSideProps: GetServerSideProps = async context => {
const id = String(context.query.id)
let initData: IReserve = null
let status: ICode = null
try {
const result = await reserveService.getReserve(id)
if (result) {
initData = result.data
}
const codeResult = await reserveService.getCode('reserve-status')
if (codeResult) {
status = codeResult.data.find(
item => item.codeId === initData?.reserveStatusId,
)
}
} catch (error) {
console.error(`reserve detail item query error ${error.message}`)
if (error.response?.data?.code === 'E003') {
return {
notFound: true,
}
}
}
return {
props: {
initData,
status,
},
}
}
export default UserReserveDetail

View File

@@ -0,0 +1,102 @@
import { BottomButtons, IButtons } from '@components/Buttons'
import ValidationAlert from '@components/ValidationAlert'
import useInputs from '@hooks/useInputs'
import { reserveService } from '@service'
import { errorStateSelector } from '@stores'
import { useRouter } from 'next/router'
import { useSnackbar } from 'notistack'
import React, { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useSetRecoilState } from 'recoil'
const ReserveCancel = () => {
const router = useRouter()
const { t } = useTranslation()
const { enqueueSnackbar } = useSnackbar()
const setErrorState = useSetRecoilState(errorStateSelector)
const searchText = useInputs('')
const [error, setError] = useState<boolean>(false)
useEffect(() => {
if (searchText.value !== '') {
setError(false)
}
}, [searchText])
const handleCancelClick = async () => {
if (searchText.value === '') {
setError(true)
return
}
try {
const result = await reserveService.cancel(
String(router.query?.id),
searchText.value,
)
if (result) {
enqueueSnackbar(
`${t('reserve')} ${t('common.cancel')}${t('common.msg.done.format')}`,
{
variant: 'success',
},
)
router.push('/user/reserve')
}
} catch (error) {
setErrorState({ error })
}
}
// 버튼
const bottomButtons = useMemo(
(): IButtons[] => [
{
id: 'item-confirm-button',
title: t('label.button.confirm'),
href: ``,
handleClick: handleCancelClick,
className: 'blue',
},
{
id: 'item-list-button',
title: t('label.button.cancel'),
href: ``,
handleClick: () => {
router.back()
},
},
],
[t, router, searchText],
)
return (
<div className="mypage">
<p>{t('reserve.msg.calcel_reason')}</p>
<div className="table_write01">
<span>{t('common.required_fields')}</span>
<div className="write">
<dl>
<dt className="import">{t('reserve.cancel_reason')}</dt>
<dd>
<input
type="text"
placeholder={t('reserve.cancel_reason')}
{...searchText}
/>
{error && (
<ValidationAlert message={t('reserve.msg.calcel_reason')} />
)}
</dd>
</dl>
</div>
</div>
<BottomButtons handleButtons={bottomButtons} />
</div>
)
}
export default ReserveCancel

View File

@@ -0,0 +1,419 @@
import {
OptionsType,
SelectBox,
SelectType,
} from '@components/Inputs/SelectBox'
import Search from '@components/Search'
import DataGridTable from '@components/TableList/DataGridTable'
import { DEFUALT_GRID_PAGE_SIZE, GRID_ROWS_PER_PAGE_OPTION } from '@constants'
import usePage from '@hooks/usePage'
import useSearchTypes from '@hooks/useSearchTypes'
import { convertStringToDateFormat } from '@libs/date'
import Typography from '@material-ui/core/Typography'
import {
GridCellParams,
GridColDef,
GridValueFormatterParams,
GridValueGetterParams,
MuiEvent,
} from '@material-ui/data-grid'
import { ICode, ILocation, Page, reserveService } from '@service'
import { conditionAtom, conditionValue, userAtom } from '@stores'
import { rownum } from '@utils'
import { GetServerSideProps } from 'next'
import { useRouter } from 'next/router'
import React, { createRef, useEffect, useMemo, useState } from 'react'
import { TFunction, useTranslation } from 'react-i18next'
import { useRecoilValue } from 'recoil'
type ColorType =
| 'inherit'
| 'initial'
| 'primary'
| 'secondary'
| 'textPrimary'
| 'textSecondary'
| 'error'
type ColumnsType = (
data: Page,
locations: OptionsType[],
categories: OptionsType[],
status: ICode[],
t?: TFunction,
) => GridColDef[]
const getColumns: ColumnsType = (data, locations, categories, status, t) => {
return [
{
field: 'rownum',
headerName: t('common.no'),
headerAlign: 'center',
align: 'center',
sortable: false,
valueGetter: (params: GridValueGetterParams) =>
rownum(data, params.api.getRowIndex(params.id), 'desc'),
},
{
field: 'locationId',
headerName: t('location'),
headerAlign: 'center',
align: 'center',
flex: 1,
sortable: false,
renderCell: (params: GridCellParams) => (
<>{locations.find(item => item.value === params.value)?.label}</>
),
},
{
field: 'categoryId',
headerName: t('reserve_item.type'),
headerAlign: 'center',
align: 'center',
flex: 1,
sortable: false,
renderCell: (params: GridCellParams) => (
<>{categories.find(item => item.value === params.value)?.label}</>
),
},
{
field: 'reserveItemName',
headerName: t('reserve_item.name'),
headerAlign: 'center',
align: 'left',
flex: 1,
sortable: false,
cellClassName: 'title',
},
{
field: 'reserveQty',
headerName: `${t('reserve.count')}/${t('reserve.number_of_people')} (${t(
'reserve_item.inventory',
)})`,
headerAlign: 'center',
align: 'center',
flex: 1,
sortable: false,
renderCell: (params: GridCellParams) => {
const category = params.row.categoryId
if (category === 'education') {
return `${params.value}(${params.row.totalQty})`
} else {
return `${params.row.totalQty}`
}
},
},
{
field: 'reserveStatusId',
headerName: t('reserve.status'),
headerAlign: 'center',
align: 'center',
flex: 1,
sortable: false,
renderCell: (params: GridCellParams) => {
let color: ColorType = 'inherit'
if (params.value === 'request' || params.value === 'cancel') {
color = 'error'
}
return (
<Typography color={color}>
{status.find(item => item.codeId === params.value)?.codeName}
</Typography>
)
},
},
{
field: 'createDate',
headerName: t('common.created_date'),
headerAlign: 'center',
align: 'center',
minWidth: 140,
sortable: false,
valueFormatter: (params: GridValueFormatterParams) =>
params.value
? convertStringToDateFormat(String(params.value), 'yyyy-MM-dd HH:mm')
: null,
},
]
}
const getXsColumns: ColumnsType = (data, locations, categories, status, t) => {
return [
{
field: 'reserveItemName',
headerName: t('reserve_item.name'),
headerAlign: 'center',
sortable: false,
renderCell,
},
]
function renderCell(params: GridCellParams) {
return (
<div>
<div className="title">{params.value}</div>
<div className="sub">
<p>
{
locations.find(item => item.value === params.row.locationId)
?.label
}
</p>
<p>
{
categories.find(item => item.value === params.row.categoryId)
?.label
}
</p>
<p>
{params.row.reserveStatusId === 'request' ||
params.row.reserveStatusId === 'cancel' ? (
<Typography component="span" color="error">
{
status.find(
item => item.codeId === params.row.reserveStatusId,
).codeName
}
</Typography>
) : (
<Typography component="span">
{
status.find(
item => item.codeId === params.row.reserveStatusId,
).codeName
}
</Typography>
)}
</p>
</div>
</div>
)
}
}
const conditionKey = 'user-reserve'
interface UserReserveProps {
locations: OptionsType[]
categories: OptionsType[]
status: ICode[]
}
const UserReserve = (props: UserReserveProps) => {
const { locations, categories, status } = props
const router = useRouter()
const { t } = useTranslation()
// 조회조건 상태관리
const keywordState = useRecoilValue(conditionAtom(conditionKey))
const pageSizeRef = createRef<SelectType>()
const user = useRecoilValue(userAtom)
const { page, setPageValue } = usePage(conditionKey, 0)
const [pageSize, setPageSize] = useState<number>(DEFUALT_GRID_PAGE_SIZE)
const [customKeyword, setCustomKeyword] = useState<conditionValue | null>({
locationId: keywordState?.locationId || '0',
categoryId: keywordState?.categoryId || 'all',
})
// 조회조건 select items
const searchTypes = useSearchTypes([
{
value: 'item',
label: t('reserve_item.name'),
},
])
const { data, mutate } = reserveService.searchUserReserve({
userId: user?.userId,
keywordType: keywordState?.keywordType || 'item',
keyword: keywordState?.keyword || '',
size: pageSize,
page,
locationId:
keywordState?.locationId !== '0' ? keywordState?.locationId : null,
categoryId:
keywordState?.categoryId !== 'all' ? keywordState?.categoryId : null,
})
useEffect(() => {
if (data) {
console.log(data)
}
}, [data])
const handleSearch = () => {
if (page === 0) {
mutate(data, false)
} else {
setPageValue(0)
}
}
const handlePageChange = (page: number, details?: any) => {
setPageValue(page)
}
const handlePageSizeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setPageSize(Number(e.target.value))
}
const handleCellClick = (
params: GridCellParams,
event: MuiEvent<React.MouseEvent>,
details?: any,
) => {
if (params.field === 'reserveItemName') {
router.push(`${router.asPath}/${params.id}`)
}
}
const handleLocationChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setCustomKeyword({
...customKeyword,
locationId: e.target.value,
})
}
const handleCategoryChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setCustomKeyword({
...customKeyword,
categoryId: e.target.value,
})
}
const columns = useMemo(
() => getColumns(data, locations, categories, status, t),
[data, t],
)
const xsColumns = useMemo(
() => getXsColumns(data, locations, categories, status, t),
[data, t],
)
const rowsPerPageSizeOptinos = GRID_ROWS_PER_PAGE_OPTION.map(item => {
return {
value: item,
label: `${item}`,
}
})
return (
<div className="mypage">
<div className="table_list01">
<fieldset>
<div>
<SelectBox
ref={pageSizeRef}
options={rowsPerPageSizeOptinos}
onChange={handlePageSizeChange}
/>
</div>
<div>
<Search
options={searchTypes}
conditionKey={conditionKey}
handleSearch={handleSearch}
customKeyword={customKeyword}
conditionNodes={
<>
{locations && (
<SelectBox
options={locations}
value={customKeyword.locationId}
onChange={handleLocationChange}
style={{ marginRight: '2px' }}
/>
)}
{categories && (
<SelectBox
options={categories}
value={customKeyword.categoryId}
onChange={handleCategoryChange}
style={{ marginRight: '2px' }}
/>
)}
</>
}
/>
</div>
</fieldset>
<DataGridTable
columns={columns}
rows={data?.content}
xsColumns={xsColumns}
getRowId={r => r.reserveId}
pageSize={pageSize}
rowCount={data?.totalElements}
page={page}
onPageChange={handlePageChange}
paginationMode="server"
onCellClick={handleCellClick}
/>
</div>
</div>
)
}
export const getServerSideProps: GetServerSideProps = async context => {
const categoryId = String(context.query.category)
let locations: OptionsType[] = []
let categories: OptionsType[] = []
let status: ICode[] = []
try {
const location = (await (
await reserveService.getLocation()
).data) as ILocation[]
if (location) {
locations = location.map(item => {
return {
value: item.locationId,
label: item.locationName,
}
})
locations.unshift({
value: '0',
label: '전체',
})
}
const category = (await (
await reserveService.getCode('reserve-category')
).data) as ICode[]
if (category) {
categories = category.map(item => {
return {
value: item.codeId,
label: item.codeName,
}
})
categories.unshift({
value: 'all',
label: '전체',
})
}
const codeResult = await reserveService.getCode('reserve-status')
if (codeResult) {
status = codeResult.data
}
} catch (error) {
console.error(`reserve detail item query error ${error.message}`)
}
return {
props: {
locations,
categories,
status,
},
}
}
export default UserReserve