feat: add conditions for read survey list on member type
This commit is contained in:
parent
15e02f60ec
commit
47be6a4433
@ -1,105 +1,211 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { prisma } from '@/libs/prisma'
|
||||
|
||||
// Types
|
||||
type SearchParams = {
|
||||
keyword?: string | null
|
||||
searchOption?: string | null
|
||||
isMySurvey?: string | null
|
||||
sort?: string | null
|
||||
offset?: string | null
|
||||
memberRole?: string | null
|
||||
store?: string | null
|
||||
builderNo?: string | null
|
||||
}
|
||||
|
||||
type WhereCondition = {
|
||||
AND?: any[]
|
||||
OR?: any[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
// Constants
|
||||
const SEARCH_OPTIONS = [
|
||||
'BUILDING_NAME',
|
||||
'REPRESENTATIVE',
|
||||
'STORE',
|
||||
'CONSTRUCTION_POINT',
|
||||
'CUSTOMER_NAME',
|
||||
'POST_CODE',
|
||||
'ADDRESS',
|
||||
'ADDRESS_DETAIL',
|
||||
] as const
|
||||
|
||||
const ITEMS_PER_PAGE = 10
|
||||
|
||||
// Helper functions
|
||||
const createKeywordSearchCondition = (keyword: string, searchOption: string): WhereCondition => {
|
||||
const where: WhereCondition = {}
|
||||
|
||||
if (searchOption === 'all') {
|
||||
where.OR = []
|
||||
|
||||
// ID 검색 조건 추가
|
||||
if (keyword.match(/^\d+$/) || !isNaN(Number(keyword))) {
|
||||
where.OR.push({
|
||||
ID: { equals: Number(keyword) },
|
||||
})
|
||||
}
|
||||
|
||||
// 다른 필드 검색 조건 추가
|
||||
where.OR.push(
|
||||
...SEARCH_OPTIONS.map((field) => ({
|
||||
[field]: { contains: keyword },
|
||||
})),
|
||||
)
|
||||
} else if (SEARCH_OPTIONS.includes(searchOption as any)) {
|
||||
where[searchOption] = { contains: keyword }
|
||||
} else if (searchOption === 'id') {
|
||||
where.ID = { equals: Number(keyword) }
|
||||
}
|
||||
|
||||
return where
|
||||
}
|
||||
|
||||
const createMemberRoleCondition = (params: SearchParams): WhereCondition => {
|
||||
const where: WhereCondition = { AND: [] }
|
||||
|
||||
switch (params.memberRole) {
|
||||
// 1차점: 같은 판매점에서 작성된 매물 + 2차점에서 제출받은 매물
|
||||
case 'Admin':
|
||||
where.OR = [
|
||||
{
|
||||
AND: [
|
||||
{ STORE: { equals: params.store } },
|
||||
{ SUBMISSION_STATUS: { equals: false } }
|
||||
]
|
||||
},
|
||||
{
|
||||
AND: [
|
||||
{ STORE: { endsWith: params.store } },
|
||||
{ SUBMISSION_STATUS: { equals: true } }
|
||||
]
|
||||
}
|
||||
]
|
||||
break
|
||||
|
||||
// 2차점: 같은 판매점에서 작성된 매물 + Builder에게 제출받은 매물
|
||||
case 'Admin_Sub':
|
||||
where.OR = [
|
||||
{
|
||||
AND: [
|
||||
{ STORE: { equals: params.store } },
|
||||
{ CONSTRUCTION_POINT: { equals: null } },
|
||||
{ SUBMISSION_STATUS: { equals: false } }
|
||||
]
|
||||
},
|
||||
{
|
||||
AND: [
|
||||
{ STORE: { equals: params.store } },
|
||||
{ CONSTRUCTION_POINT: { not: null } },
|
||||
{ SUBMISSION_STATUS: { equals: true } }
|
||||
]
|
||||
}
|
||||
]
|
||||
break
|
||||
|
||||
// 2차점 시공권한: 같은 시공ID에서 작성된 매물
|
||||
case 'Builder':
|
||||
where.AND?.push({
|
||||
CONSTRUCTION_POINT: { equals: params.builderNo },
|
||||
SUBMISSION_STATUS: { equals: false },
|
||||
})
|
||||
break
|
||||
|
||||
// 시공점: 같은 시공ID에서 작성된 매물
|
||||
case 'Partner':
|
||||
where.AND?.push({
|
||||
CONSTRUCTION_POINT: { equals: params.builderNo },
|
||||
SUBMISSION_STATUS: { equals: false },
|
||||
})
|
||||
break
|
||||
|
||||
// 모든 매물 조회 가능
|
||||
case 'T01':
|
||||
case 'User':
|
||||
break
|
||||
}
|
||||
|
||||
return where
|
||||
}
|
||||
|
||||
// API Routes
|
||||
export async function POST(request: Request) {
|
||||
const body = await request.json()
|
||||
// @ts-ignore
|
||||
const res = await prisma.SD_SURVEY_SALES_BASIC_INFO.create({
|
||||
data: body,
|
||||
})
|
||||
return NextResponse.json(res)
|
||||
try {
|
||||
const body = await request.json()
|
||||
// @ts-ignore
|
||||
const res = await prisma.SD_SURVEY_SALES_BASIC_INFO.create({
|
||||
data: body,
|
||||
})
|
||||
return NextResponse.json(res)
|
||||
} catch (error) {
|
||||
console.error('Error creating survey:', error)
|
||||
return NextResponse.json({ error: 'Failed to create survey' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const keyword = searchParams.get('keyword')
|
||||
const searchOption = searchParams.get('searchOption')
|
||||
const isMySurvey = searchParams.get('isMySurvey')
|
||||
const sort = searchParams.get('sort')
|
||||
const offset = searchParams.get('offset')
|
||||
const store = searchParams.get('store')
|
||||
const construction_point = searchParams.get('construction_point')
|
||||
|
||||
const searchOptions = ['BUILDING_NAME', 'REPRESENTATIVE', 'STORE', 'CONSTRUCTION_POINT', 'CUSTOMER_NAME', 'POST_CODE', 'ADDRESS', 'ADDRESS_DETAIL']
|
||||
try {
|
||||
const where: any = {}
|
||||
|
||||
if (isMySurvey !== null && isMySurvey !== undefined) {
|
||||
where.REPRESENTATIVE = isMySurvey
|
||||
const { searchParams } = new URL(request.url)
|
||||
const params: SearchParams = {
|
||||
keyword: searchParams.get('keyword'),
|
||||
searchOption: searchParams.get('searchOption'),
|
||||
isMySurvey: searchParams.get('isMySurvey'),
|
||||
sort: searchParams.get('sort'),
|
||||
offset: searchParams.get('offset'),
|
||||
memberRole: searchParams.get('memberRole'),
|
||||
store: searchParams.get('store'),
|
||||
builderNo: searchParams.get('builderNo'),
|
||||
}
|
||||
|
||||
if (keyword && keyword.trim() !== '' && searchOption) {
|
||||
if (searchOption === 'all') {
|
||||
where.OR = []
|
||||
if (keyword.match(/^\d+$/) || !isNaN(Number(keyword))) {
|
||||
where.OR.push({
|
||||
ID: {
|
||||
equals: Number(keyword),
|
||||
},
|
||||
})
|
||||
}
|
||||
where.OR.push(
|
||||
...searchOptions.map((field) => ({
|
||||
[field]: {
|
||||
contains: keyword,
|
||||
},
|
||||
})),
|
||||
)
|
||||
} else if (searchOptions.includes(searchOption)) {
|
||||
where[searchOption] = {
|
||||
contains: keyword,
|
||||
}
|
||||
} else if (searchOption === 'id') {
|
||||
where[searchOption] = {
|
||||
equals: Number(keyword),
|
||||
}
|
||||
}
|
||||
const where: WhereCondition = {}
|
||||
|
||||
// 내가 작성한 매물 조건
|
||||
if (params.isMySurvey) {
|
||||
where.REPRESENTATIVE = params.isMySurvey
|
||||
}
|
||||
|
||||
where.AND = []
|
||||
if (store) {
|
||||
where.AND.push({
|
||||
STORE: {
|
||||
equals: store,
|
||||
},
|
||||
})
|
||||
}
|
||||
if (construction_point) {
|
||||
where.AND.push({
|
||||
CONSTRUCTION_POINT: {
|
||||
equals: construction_point,
|
||||
},
|
||||
})
|
||||
// 키워드 검색 조건
|
||||
if (params.keyword && params.searchOption) {
|
||||
Object.assign(where, createKeywordSearchCondition(params.keyword, params.searchOption))
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
// 회원 유형 조건
|
||||
Object.assign(where, createMemberRoleCondition(params))
|
||||
|
||||
// 데이터 조회
|
||||
if (params.offset) {
|
||||
// @ts-ignore
|
||||
const res = await prisma.SD_SURVEY_SALES_BASIC_INFO.findMany({
|
||||
where,
|
||||
orderBy: sort === 'created' ? { REG_DT: 'desc' } : { UPT_DT: 'desc' },
|
||||
skip: Number(offset),
|
||||
take: 10,
|
||||
orderBy: params.sort === 'created' ? { REG_DT: 'desc' } : { UPT_DT: 'desc' },
|
||||
skip: Number(params.offset),
|
||||
take: ITEMS_PER_PAGE,
|
||||
})
|
||||
return NextResponse.json(res)
|
||||
} else {
|
||||
// @ts-ignore
|
||||
const count = await prisma.SD_SURVEY_SALES_BASIC_INFO.count({
|
||||
where,
|
||||
})
|
||||
return NextResponse.json(count)
|
||||
}
|
||||
|
||||
// 전체 개수 조회
|
||||
// @ts-ignore
|
||||
const count = await prisma.SD_SURVEY_SALES_BASIC_INFO.count({ where })
|
||||
return NextResponse.json(count)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
throw error
|
||||
console.error('Error fetching surveys:', error)
|
||||
return NextResponse.json({ error: 'Failed to fetch surveys' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
export async function PUT(request: Request) {
|
||||
const body = await request.json()
|
||||
const detailInfo = { ...body.detail_info, BASIC_INFO_ID: body.id }
|
||||
// @ts-ignore
|
||||
const res = await prisma.SD_SURVEY_SALES_DETAIL_INFO.create({
|
||||
data: detailInfo,
|
||||
})
|
||||
return NextResponse.json({ message: 'Survey sales updated successfully' })
|
||||
try {
|
||||
const body = await request.json()
|
||||
const detailInfo = { ...body.detail_info, BASIC_INFO_ID: body.id }
|
||||
// @ts-ignore
|
||||
const res = await prisma.SD_SURVEY_SALES_DETAIL_INFO.create({
|
||||
data: detailInfo,
|
||||
})
|
||||
return NextResponse.json({ message: 'Survey sales updated successfully' })
|
||||
} catch (error) {
|
||||
console.error('Error updating survey:', error)
|
||||
return NextResponse.json({ error: 'Failed to update survey' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,20 +8,20 @@ export default function DetailButton({ isTemporary, surveyId, representative }:
|
||||
const router = useRouter()
|
||||
const { session } = useSessionStore()
|
||||
const { submitSurvey, deleteSurvey } = useServey(surveyId)
|
||||
const [userNm, setUserNm] = useState('')
|
||||
const [userId, setUserId] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (session?.isLoggedIn) {
|
||||
setUserNm(session?.userNm ?? '')
|
||||
setUserId(session?.userId ?? '')
|
||||
}
|
||||
}, [session, setUserNm])
|
||||
}, [session, setUserId])
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (isTemporary) {
|
||||
alert('一時保存されたデータは提出できません。')
|
||||
return
|
||||
}
|
||||
if (userNm === representative) {
|
||||
if (userId === representative) {
|
||||
if (confirm('提出しますか??')) {
|
||||
if (surveyId) {
|
||||
// TODO: 제출 페이지 추가
|
||||
@ -34,7 +34,7 @@ export default function DetailButton({ isTemporary, surveyId, representative }:
|
||||
}
|
||||
}
|
||||
const handleUpdate = () => {
|
||||
if (userNm === representative) {
|
||||
if (userId === representative) {
|
||||
router.push(`/survey-sale/basic-info?id=${surveyId}&isTemp=${isTemporary}`)
|
||||
} else {
|
||||
alert('担当者のみ修正可能です。')
|
||||
@ -43,7 +43,7 @@ export default function DetailButton({ isTemporary, surveyId, representative }:
|
||||
const handleDelete = async () => {
|
||||
if (confirm('削除しますか?')) {
|
||||
if (surveyId) {
|
||||
if (userNm === representative) {
|
||||
if (userId === representative) {
|
||||
await deleteSurvey()
|
||||
router.push('/survey-sale')
|
||||
} else {
|
||||
|
||||
@ -37,7 +37,7 @@ export default function BasicForm() {
|
||||
const [basicInfoData, setBasicInfoData] = useState<SurveyBasicRequest>(defaultBasicInfoForm)
|
||||
|
||||
const { addressData } = useAddressStore()
|
||||
const { userType, store, construction_point } = useUserType()
|
||||
const { memberRole, store, builderNo } = useUserType()
|
||||
const { session } = useSessionStore()
|
||||
|
||||
const popupController = usePopupController()
|
||||
@ -58,11 +58,13 @@ export default function BasicForm() {
|
||||
if (session?.isLoggedIn) {
|
||||
setBasicInfoData((prev) => ({
|
||||
...prev,
|
||||
REPRESENTATIVE: session?.userNm ?? '',
|
||||
REPRESENTATIVE: session?.userId ?? '',
|
||||
STORE: store ?? '',
|
||||
CONSTRUCTION_POINT: builderNo ?? '',
|
||||
}))
|
||||
}
|
||||
setBasicInfoSelected()
|
||||
}, [surveyDetail, addressData, session?.isLoggedIn, session?.userNm])
|
||||
}, [surveyDetail, addressData, session?.isLoggedIn, session?.userNm, store, builderNo])
|
||||
|
||||
const focusInput = (input: keyof SurveyBasicRequest) => {
|
||||
const inputElement = document.getElementById(input)
|
||||
@ -117,11 +119,11 @@ export default function BasicForm() {
|
||||
type="text"
|
||||
className="input-frame"
|
||||
id="representative"
|
||||
value={session?.userNm ? session?.userNm : basicInfoData.REPRESENTATIVE}
|
||||
value={session?.userId ? session?.userId : basicInfoData.REPRESENTATIVE}
|
||||
onChange={(e) => handleChange('REPRESENTATIVE', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{(userType === 'order' || userType?.includes('musubi')) && (
|
||||
{(memberRole === 'Builder' || memberRole?.includes('Admin')) && (
|
||||
<>
|
||||
<div className="data-input-form-bx">
|
||||
<div className="data-input-form-tit">販売店</div>
|
||||
@ -135,14 +137,14 @@ export default function BasicForm() {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{(userType === 'partner' || userType === 'musubi_con') && (
|
||||
{(memberRole === 'Partner' || memberRole === 'Builder') && (
|
||||
<div className="data-input-form-bx">
|
||||
<div className="data-input-form-tit">施工店</div>
|
||||
<input
|
||||
type="text"
|
||||
className="input-frame"
|
||||
id="construction_point"
|
||||
value={construction_point ? construction_point : basicInfoData.CONSTRUCTION_POINT ?? ''}
|
||||
value={builderNo ? builderNo : basicInfoData.CONSTRUCTION_POINT ?? ''}
|
||||
onChange={(e) => handleChange('CONSTRUCTION_POINT', e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -6,7 +6,8 @@ import { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import SearchForm from './SearchForm'
|
||||
import { useSurveyFilterStore } from '@/store/surveyFilterStore'
|
||||
import { UserType } from '@/hooks/useUserType'
|
||||
import { MemberRole } from '@/hooks/useUserType'
|
||||
import { useSessionStore } from '@/store/session'
|
||||
|
||||
export default function ListTable() {
|
||||
const router = useRouter()
|
||||
@ -15,7 +16,9 @@ export default function ListTable() {
|
||||
|
||||
const [heldSurveyList, setHeldSurveyList] = useState<typeof surveyList>([])
|
||||
const [hasMore, setHasMore] = useState(false)
|
||||
const [memberType, setMemberType] = useState<UserType>('hwj')
|
||||
const [memberRole, setMemberRole] = useState<MemberRole>()
|
||||
|
||||
const { session } = useSessionStore()
|
||||
|
||||
useEffect(() => {
|
||||
if (surveyList && surveyList.length > 0) {
|
||||
@ -29,9 +32,8 @@ export default function ListTable() {
|
||||
}
|
||||
setHasMore(surveyListCount > offset + 10)
|
||||
}
|
||||
// 회원 유형 설정 이후 변경
|
||||
setMemberType('hwj')
|
||||
}, [surveyList, surveyListCount, offset])
|
||||
setMemberRole(session.role as MemberRole)
|
||||
}, [surveyList, surveyListCount, offset, session])
|
||||
|
||||
const handleDetailClick = (id: number) => {
|
||||
router.push(`/survey-sale/${id}`)
|
||||
@ -45,7 +47,7 @@ export default function ListTable() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm onItemsInit={handleItemsInit} memberType={memberType} />
|
||||
<SearchForm onItemsInit={handleItemsInit} memberRole={memberRole as MemberRole} />
|
||||
{heldSurveyList.length > 0 ? (
|
||||
<div className="sale-frame">
|
||||
<ul className="sale-list-wrap">
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { SEARCH_OPTIONS, SEARCH_OPTIONS_ENUM, SEARCH_OPTIONS_PARTNERS, useSurveyFilterStore } from '@/store/surveyFilterStore'
|
||||
import { UserType } from '@/hooks/useUserType'
|
||||
import { MemberRole } from '@/hooks/useUserType'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function SearchForm({ onItemsInit, memberType }: { onItemsInit: () => void; memberType: UserType }) {
|
||||
export default function SearchForm({ onItemsInit, memberRole }: { onItemsInit: () => void; memberRole: MemberRole }) {
|
||||
const router = useRouter()
|
||||
const { setSearchOption, setSort, setIsMySurvey, setKeyword, isMySurvey, keyword, searchOption, sort } = useSurveyFilterStore()
|
||||
const [searchKeyword, setSearchKeyword] = useState(keyword)
|
||||
@ -20,7 +20,7 @@ export default function SearchForm({ onItemsInit, memberType }: { onItemsInit: (
|
||||
setKeyword(searchKeyword)
|
||||
onItemsInit()
|
||||
}
|
||||
const searchOptions = memberType === 'partner' ? SEARCH_OPTIONS_PARTNERS : SEARCH_OPTIONS
|
||||
const searchOptions = memberRole === 'Partner' ? SEARCH_OPTIONS_PARTNERS : SEARCH_OPTIONS
|
||||
|
||||
return (
|
||||
<div className="sale-frame">
|
||||
|
||||
@ -41,13 +41,13 @@ export function useServey(id?: number): {
|
||||
} {
|
||||
const queryClient = useQueryClient()
|
||||
const { keyword, searchOption, isMySurvey, sort, offset } = useSurveyFilterStore()
|
||||
const { store, construction_point } = useUserType()
|
||||
const { store, builderNo, memberRole } = useUserType()
|
||||
|
||||
const { data: surveyList, isLoading: isLoadingSurveyList } = useQuery({
|
||||
queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort, offset, store, construction_point],
|
||||
queryKey: ['survey', 'list', keyword, searchOption, isMySurvey, sort, offset, store, builderNo, memberRole],
|
||||
queryFn: async () => {
|
||||
const resp = await axiosInstance(null).get<SurveyBasicInfo[]>('/api/survey-sales', {
|
||||
params: { keyword, searchOption, isMySurvey, sort, offset, store, construction_point },
|
||||
params: { keyword, searchOption, isMySurvey, sort, offset, store, builderNo, memberRole },
|
||||
})
|
||||
return resp.data
|
||||
},
|
||||
|
||||
@ -1,24 +1,31 @@
|
||||
import { useSessionStore } from '@/store/session'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export type UserType = 'hwj' | 'order' | 'musubi' | 'musubi_con' | 'partner'
|
||||
export type MemberRole = 'T01' | 'Admin' | 'Admin_Sub' | 'Builder' | 'Partner' | 'User'
|
||||
// TO1 - else
|
||||
// Admin - 1차점, Admin_Sub - 2차점, Builder - 2차점 시공사, Partner - 파트너사, User - else
|
||||
|
||||
// 로그인 된 회원 유형에 따라 조사 매물 목록 변경됨
|
||||
export function useUserType() {
|
||||
const { session } = useSessionStore()
|
||||
const [userType, setUserType] = useState<UserType | null>(null)
|
||||
const [memberRole, setMemberRole] = useState<MemberRole | null>(null)
|
||||
const [store, setStore] = useState<string | null>(null)
|
||||
const [construction_point, setConstructionPoint] = useState<string | null>(null)
|
||||
const [builderNo, setBuilderNo] = useState<string | null>(null)
|
||||
|
||||
// TODO: 회원 유형 설정
|
||||
useEffect(() => {
|
||||
if (!session?.isLoggedIn) return
|
||||
setUserType('musubi_con')
|
||||
setMemberRole(session.role as MemberRole)
|
||||
if (session.role === 'T01') {
|
||||
setStore(null)
|
||||
} else {
|
||||
setStore(session.storeId)
|
||||
}
|
||||
setBuilderNo(session.builderNo)
|
||||
}, [session])
|
||||
|
||||
return {
|
||||
userType,
|
||||
memberRole,
|
||||
store,
|
||||
construction_point,
|
||||
builderNo,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user