| @@ -29,6 +29,7 @@ export const ApiId = { | |||||
| // 駐車場関連 ---------------------------------- | // 駐車場関連 ---------------------------------- | ||||
| 駐車場マスタ一覧取得: id++, | 駐車場マスタ一覧取得: id++, | ||||
| サービス券マスタ一覧取得: id++, | |||||
| // 店舗関連関連 ---------------------------------- | // 店舗関連関連 ---------------------------------- | ||||
| 店舗一覧取得: id++, | 店舗一覧取得: id++, | ||||
| @@ -37,8 +38,11 @@ export const ApiId = { | |||||
| デポジットチャージ: id++, | デポジットチャージ: id++, | ||||
| 店舗設定: id++, | 店舗設定: id++, | ||||
| 店舗QR設定取得: id++, | 店舗QR設定取得: id++, | ||||
| 店舗QR設定認証設定新規登録: id++, | |||||
| 店舗QR設定認証設定更新: id++, | |||||
| 店舗QR設定認証設定追加: id++, | 店舗QR設定認証設定追加: id++, | ||||
| 店舗QR設定認証設定削除: id++, | 店舗QR設定認証設定削除: id++, | ||||
| 店舗QR設定認証設定全削除: id++, | |||||
| 店舗QR設定取得設定変更: id++, | 店舗QR設定取得設定変更: id++, | ||||
| 店舗QR設定取得設定無効化: id++, | 店舗QR設定取得設定無効化: id++, | ||||
| @@ -1,10 +1,14 @@ | |||||
| import { APICommonResponse, ApiId, HttpMethod, request } from "api"; | |||||
| import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "api"; | |||||
| import { getUrl } from "./url"; | import { getUrl } from "./url"; | ||||
| export type 駐車場マスタ = { | export type 駐車場マスタ = { | ||||
| parking_management_code: string; | parking_management_code: string; | ||||
| parking_name: string; | parking_name: string; | ||||
| }; | }; | ||||
| export type サービス券マスタ = { | |||||
| discount_ticket_code: number; | |||||
| ticket_name: string; | |||||
| }; | |||||
| // -------駐車場マスタ一覧取得--------------- | // -------駐車場マスタ一覧取得--------------- | ||||
| export type 駐車場マスタ一覧取得Request = {}; | export type 駐車場マスタ一覧取得Request = {}; | ||||
| @@ -23,3 +27,23 @@ export const 駐車場マスタ一覧取得 = async ( | |||||
| }); | }); | ||||
| return res; | return res; | ||||
| }; | }; | ||||
| // -------サービス券マスタ一覧取得--------------- | |||||
| export type サービス券マスタ一覧取得Request = { | |||||
| parking_management_code: string; | |||||
| }; | |||||
| export type サービス券マスタ一覧取得Response = { | |||||
| data: { | |||||
| list: サービス券マスタ[]; | |||||
| }; | |||||
| } & APICommonResponse; | |||||
| export const サービス券マスタ一覧取得 = async ( | |||||
| param: サービス券マスタ一覧取得Request | |||||
| ) => { | |||||
| const res = await request<サービス券マスタ一覧取得Response>({ | |||||
| url: getUrl(ApiId.サービス券マスタ一覧取得), | |||||
| method: HttpMethod.GET, | |||||
| data: new URLSearchParams(param), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| @@ -12,9 +12,10 @@ export type 店舗 = { | |||||
| }; | }; | ||||
| export type QRサービス券認証設定 = { | export type QRサービス券認証設定 = { | ||||
| shop_no: number; | |||||
| parking_management_code: string; | parking_management_code: string; | ||||
| parking_name: string; | parking_name: string; | ||||
| discount_ticket_code: number; | |||||
| discount_ticket_code: number | null; | |||||
| }; | }; | ||||
| export type QRサービス券取得設定 = { | export type QRサービス券取得設定 = { | ||||
| qr_service_parking_group_id: string; | qr_service_parking_group_id: string; | ||||
| @@ -140,6 +141,95 @@ export const 店舗QR設定取得 = async (param: 店舗QR設定取得Request) = | |||||
| return res; | return res; | ||||
| }; | }; | ||||
| // -------店舗QR設定認証設定新規登録--------------- | |||||
| export type 店舗QR設定認証設定新規登録Request = { | |||||
| shop_id: string; | |||||
| parking_management_code: string; | |||||
| shop_no: string; | |||||
| }; | |||||
| export type 店舗QR設定認証設定新規登録Response = {} & APICommonResponse; | |||||
| export const 店舗QR設定認証設定新規登録 = async ( | |||||
| param: 店舗QR設定認証設定新規登録Request | |||||
| ) => { | |||||
| const res = await request<店舗QR設定認証設定新規登録Response>({ | |||||
| url: getUrl(ApiId.店舗QR設定認証設定新規登録), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(param), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| // -------店舗QR設定認証設定更新--------------- | |||||
| export type 店舗QR設定認証設定更新Request = { | |||||
| shop_id: string; | |||||
| parking_management_code: string; | |||||
| shop_no: string; | |||||
| }; | |||||
| export type 店舗QR設定認証設定更新Response = {} & APICommonResponse; | |||||
| export const 店舗QR設定認証設定更新 = async ( | |||||
| param: 店舗QR設定認証設定更新Request | |||||
| ) => { | |||||
| const res = await request<店舗QR設定認証設定更新Response>({ | |||||
| url: getUrl(ApiId.店舗QR設定認証設定更新), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(param), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| // -------店舗QR設定認証設定追加--------------- | |||||
| export type 店舗QR設定認証設定追加Request = { | |||||
| shop_id: string; | |||||
| parking_management_code: string; | |||||
| discount_ticket_code: string; | |||||
| }; | |||||
| export type 店舗QR設定認証設定追加Response = {} & APICommonResponse; | |||||
| export const 店舗QR設定認証設定追加 = async ( | |||||
| param: 店舗QR設定認証設定追加Request | |||||
| ) => { | |||||
| const res = await request<店舗QR設定認証設定追加Response>({ | |||||
| url: getUrl(ApiId.店舗QR設定認証設定追加), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(param), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| // -------店舗QR設定認証設定削除--------------- | |||||
| export type 店舗QR設定認証設定削除Request = { | |||||
| shop_id: string; | |||||
| parking_management_code: string; | |||||
| discount_ticket_code: string; | |||||
| }; | |||||
| export type 店舗QR設定認証設定削除Response = {} & APICommonResponse; | |||||
| export const 店舗QR設定認証設定削除 = async ( | |||||
| param: 店舗QR設定認証設定削除Request | |||||
| ) => { | |||||
| const res = await request<店舗QR設定認証設定削除Response>({ | |||||
| url: getUrl(ApiId.店舗QR設定認証設定削除), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(param), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| // -------店舗QR設定認証設定削除--------------- | |||||
| export type 店舗QR設定認証設定全削除Request = { | |||||
| shop_id: string; | |||||
| parking_management_code: string; | |||||
| }; | |||||
| export type 店舗QR設定認証設定全削除Response = {} & APICommonResponse; | |||||
| export const 店舗QR設定認証設定全削除 = async ( | |||||
| param: 店舗QR設定認証設定全削除Request | |||||
| ) => { | |||||
| const res = await request<店舗QR設定認証設定全削除Response>({ | |||||
| url: getUrl(ApiId.店舗QR設定認証設定全削除), | |||||
| method: HttpMethod.POST, | |||||
| data: makeParam(param), | |||||
| }); | |||||
| return res; | |||||
| }; | |||||
| // -------店舗QR設定取得設定変更--------------- | // -------店舗QR設定取得設定変更--------------- | ||||
| export type 店舗QR設定取得設定変更Request = { | export type 店舗QR設定取得設定変更Request = { | ||||
| shop_id: string; | shop_id: string; | ||||
| @@ -24,6 +24,7 @@ const urls = { | |||||
| // 駐車場関連 ---------------------------------- | // 駐車場関連 ---------------------------------- | ||||
| [A.駐車場マスタ一覧取得]: "parking/list", | [A.駐車場マスタ一覧取得]: "parking/list", | ||||
| [A.サービス券マスタ一覧取得]: "parking/discount-ticket/list", | |||||
| // 店舗関連関連 ---------------------------------- | // 店舗関連関連 ---------------------------------- | ||||
| [A.店舗一覧取得]: "shop/list", | [A.店舗一覧取得]: "shop/list", | ||||
| @@ -33,8 +34,11 @@ const urls = { | |||||
| [A.店舗設定]: "shop/config", | [A.店舗設定]: "shop/config", | ||||
| [A.店舗設定]: "shop/config", | [A.店舗設定]: "shop/config", | ||||
| [A.店舗QR設定取得]: "shop/config/detail", | [A.店舗QR設定取得]: "shop/config/detail", | ||||
| [A.店舗QR設定認証設定新規登録]: "shop/config/certification/register", | |||||
| [A.店舗QR設定認証設定更新]: "shop/config/certification/update", | |||||
| [A.店舗QR設定認証設定追加]: "shop/config/certification/add", | [A.店舗QR設定認証設定追加]: "shop/config/certification/add", | ||||
| [A.店舗QR設定認証設定削除]: "shop/config/certification/remove", | [A.店舗QR設定認証設定削除]: "shop/config/certification/remove", | ||||
| [A.店舗QR設定認証設定全削除]: "shop/config/certification/delete", | |||||
| [A.店舗QR設定取得設定変更]: "shop/config/acquisition/enable", | [A.店舗QR設定取得設定変更]: "shop/config/acquisition/enable", | ||||
| [A.店舗QR設定取得設定無効化]: "shop/config/acquisition/disable", | [A.店舗QR設定取得設定無効化]: "shop/config/acquisition/disable", | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { HasChildren } from "@types"; | import { HasChildren } from "@types"; | ||||
| import { 駐車場マスタ } from "api/parking"; | |||||
| import { | import { | ||||
| QRサービス券取得設定, | QRサービス券取得設定, | ||||
| QRサービス券認証設定, | QRサービス券認証設定, | ||||
| @@ -15,11 +16,13 @@ import { PageID, TabID } from "pages"; | |||||
| import { createContext, useContext, useEffect, useState } from "react"; | import { createContext, useContext, useEffect, useState } from "react"; | ||||
| import { useParams } from "react-router-dom"; | import { useParams } from "react-router-dom"; | ||||
| import { getPath } from "routes/path"; | import { getPath } from "routes/path"; | ||||
| import 駐車場マスタストア from "storage/cache/駐車場マスタ"; | |||||
| type Context = { | type Context = { | ||||
| shop: 店舗 | null; | shop: 店舗 | null; | ||||
| certificationSetting: QRサービス券認証設定[]; | certificationSetting: QRサービス券認証設定[]; | ||||
| acquisitionSetting: QRサービス券取得設定 | null; | acquisitionSetting: QRサービス券取得設定 | null; | ||||
| parkings: 駐車場マスタ[]; | |||||
| fetch: () => Promise<void>; | fetch: () => Promise<void>; | ||||
| moveToMain: VoidFunction; | moveToMain: VoidFunction; | ||||
| }; | }; | ||||
| @@ -28,6 +31,7 @@ export const 店舗詳細Context = createContext<Context>({ | |||||
| shop: null, | shop: null, | ||||
| certificationSetting: [], | certificationSetting: [], | ||||
| acquisitionSetting: null, | acquisitionSetting: null, | ||||
| parkings: [], | |||||
| fetch: async () => {}, | fetch: async () => {}, | ||||
| moveToMain: () => {}, | moveToMain: () => {}, | ||||
| }); | }); | ||||
| @@ -37,6 +41,7 @@ function 店舗詳細ContextProvider({ children }: Props) { | |||||
| const { shopId: paramShopId } = useParams(); | const { shopId: paramShopId } = useParams(); | ||||
| const [shop, setShop] = useState<店舗 | null>(null); | const [shop, setShop] = useState<店舗 | null>(null); | ||||
| const [parkings, setParkings] = useState<駐車場マスタ[]>([]); | |||||
| const [certificationSetting, setCertificationSetting] = useState< | const [certificationSetting, setCertificationSetting] = useState< | ||||
| QRサービス券認証設定[] | QRサービス券認証設定[] | ||||
| >([]); | >([]); | ||||
| @@ -105,12 +110,19 @@ function 店舗詳細ContextProvider({ children }: Props) { | |||||
| fetch(); | fetch(); | ||||
| }, []); | }, []); | ||||
| useEffect(() => { | |||||
| 駐車場マスタストア.get().then((parkings) => { | |||||
| setParkings(parkings); | |||||
| }); | |||||
| }, []); | |||||
| return ( | return ( | ||||
| <店舗詳細Context.Provider | <店舗詳細Context.Provider | ||||
| value={{ | value={{ | ||||
| shop, | shop, | ||||
| certificationSetting, | certificationSetting, | ||||
| acquisitionSetting, | acquisitionSetting, | ||||
| parkings, | |||||
| fetch, | fetch, | ||||
| moveToMain, | moveToMain, | ||||
| }} | }} | ||||
| @@ -3,19 +3,22 @@ import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Co | |||||
| import useDashboard from "hooks/useDashBoard"; | import useDashboard from "hooks/useDashBoard"; | ||||
| import { PageID, TabID } from "pages"; | import { PageID, TabID } from "pages"; | ||||
| import { useContext } from "react"; | import { useContext } from "react"; | ||||
| import 駐車場一覧 from "./駐車場一覧"; | |||||
| import 駐車場追加 from "./駐車場追加"; | |||||
| import AddParking from "./駐車場追加"; | |||||
| import ParkingList from "./駐車場一覧"; | |||||
| export default function Page() { | export default function Page() { | ||||
| const {} = useDashboard(PageID.店舗詳細, TabID.店舗詳細_QR認証設定); | const {} = useDashboard(PageID.店舗詳細, TabID.店舗詳細_QR認証設定); | ||||
| const {} = useContext(店舗詳細Context); | |||||
| const { shop } = useContext(店舗詳細Context); | |||||
| if (!shop) { | |||||
| return null; | |||||
| } | |||||
| return ( | return ( | ||||
| <Box> | <Box> | ||||
| <Stack spacing={2}> | <Stack spacing={2}> | ||||
| <駐車場一覧 /> | |||||
| <駐車場追加 /> | |||||
| <AddParking /> | |||||
| <ParkingList /> | |||||
| </Stack> | </Stack> | ||||
| </Box> | </Box> | ||||
| ); | ); | ||||
| @@ -1,99 +0,0 @@ | |||||
| import { Box, Button, Card, Grid, Stack, Typography } from "@mui/material"; | |||||
| import { 駐車場マスタ } from "api/parking"; | |||||
| import { QRサービス券駐車場グループ駐車場削除登録 } from "api/qr-service"; | |||||
| import { QRサービス券駐車場グループ管理Context } from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import { useDialog } from "hooks/useDialog"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import { useContext, useEffect, useState } from "react"; | |||||
| export default function 駐車場一覧() { | |||||
| const { fetch, selectedGroup } = useContext( | |||||
| QRサービス券駐車場グループ管理Context | |||||
| ); | |||||
| const { success, error } = useSnackbarCustom(); | |||||
| const { callAPI: callQRサービス券駐車場グループ駐車場削除登録 } = useAPICall({ | |||||
| apiMethod: QRサービス券駐車場グループ駐車場削除登録, | |||||
| backDrop: true, | |||||
| onSuccess: () => { | |||||
| success("削除しました"); | |||||
| fetch(); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const [削除予定駐車場管理コード, set削除予定駐車場管理コード] = useState< | |||||
| string | null | |||||
| >(null); | |||||
| const { element, open, isAgree } = useDialog({ | |||||
| message: "削除しますか?", | |||||
| }); | |||||
| const deleteDataConfirm = (parkingManagementCode: string) => { | |||||
| set削除予定駐車場管理コード(parkingManagementCode); | |||||
| open(); | |||||
| }; | |||||
| useEffect(() => { | |||||
| if (isAgree && selectedGroup && 削除予定駐車場管理コード) { | |||||
| callQRサービス券駐車場グループ駐車場削除登録({ | |||||
| id: selectedGroup.id, | |||||
| parking_management_code: 削除予定駐車場管理コード, | |||||
| }); | |||||
| } | |||||
| }, [isAgree]); | |||||
| if (selectedGroup === null) { | |||||
| return null; | |||||
| } | |||||
| return ( | |||||
| <Card sx={{ p: 2 }} elevation={1}> | |||||
| <Box> | |||||
| <Stack spacing={2}> | |||||
| <Typography variant="h6">グループに含まれる駐車場</Typography> | |||||
| <Stack spacing={1}> | |||||
| {selectedGroup.parkings.map((p) => ( | |||||
| <Row | |||||
| parking={p} | |||||
| key={p.parking_management_code} | |||||
| deleteData={deleteDataConfirm} | |||||
| /> | |||||
| ))} | |||||
| {selectedGroup.parkings.length === 0 && ( | |||||
| <Typography>登録なし</Typography> | |||||
| )} | |||||
| </Stack> | |||||
| </Stack> | |||||
| </Box> | |||||
| {element} | |||||
| </Card> | |||||
| ); | |||||
| } | |||||
| type RowProps = { | |||||
| parking: 駐車場マスタ; | |||||
| deleteData: (parkingManagementCode: string) => void; | |||||
| }; | |||||
| function Row({ parking, deleteData }: RowProps) { | |||||
| const handleClick = () => { | |||||
| deleteData(parking.parking_management_code); | |||||
| }; | |||||
| return ( | |||||
| <Grid container> | |||||
| <Grid item xs={10}> | |||||
| {parking.parking_name}({parking.parking_management_code}) | |||||
| </Grid> | |||||
| <Grid item xs={2}> | |||||
| <Button color="error" onClick={handleClick}> | |||||
| 削除 | |||||
| </Button> | |||||
| </Grid> | |||||
| </Grid> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,98 @@ | |||||
| import { Box, Card, Stack, Typography } from "@mui/material"; | |||||
| import { QRサービス券認証設定, 店舗QR設定認証設定全削除 } from "api/shop"; | |||||
| import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import { useDialog } from "hooks/useDialog"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import { has } from "lodash"; | |||||
| import { useContext, useEffect, useMemo, useState } from "react"; | |||||
| import RowData from "./駐車場設定"; | |||||
| type 駐車場ごと設定 = { | |||||
| [parking_management_code: string]: QRサービス券認証設定[]; | |||||
| }; | |||||
| export default function Page() { | |||||
| const { shop, fetch, certificationSetting } = useContext(店舗詳細Context); | |||||
| const { success, error } = useSnackbarCustom(); | |||||
| const 駐車場ごと設定: 駐車場ごと設定 = useMemo(() => { | |||||
| const ret: 駐車場ごと設定 = {}; | |||||
| certificationSetting.forEach((ele) => { | |||||
| if (has(ret, ele.parking_management_code)) { | |||||
| ret[ele.parking_management_code].push(ele); | |||||
| } else { | |||||
| ret[ele.parking_management_code] = [ele]; | |||||
| } | |||||
| }); | |||||
| return ret; | |||||
| }, [certificationSetting]); | |||||
| const { callAPI: call店舗QR設定認証設定全削除 } = useAPICall({ | |||||
| apiMethod: 店舗QR設定認証設定全削除, | |||||
| backDrop: true, | |||||
| onSuccess: () => { | |||||
| fetch(); | |||||
| success("削除しました"); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const [ | |||||
| tmpDeleteTargetParkingMangementCode, | |||||
| setTmpDeleteTargetParkingMangementCode, | |||||
| ] = useState(""); | |||||
| const deleteParkingSetting = (parkingManagementCode: string) => { | |||||
| setTmpDeleteTargetParkingMangementCode(parkingManagementCode); | |||||
| OpenDeleteConfirmDialog(); | |||||
| }; | |||||
| const { | |||||
| isAgree, | |||||
| element: dialog, | |||||
| open: OpenDeleteConfirmDialog, | |||||
| } = useDialog({ | |||||
| message: "削除しますか", | |||||
| }); | |||||
| useEffect(() => { | |||||
| if ( | |||||
| isAgree === true && | |||||
| tmpDeleteTargetParkingMangementCode && | |||||
| shop !== null | |||||
| ) { | |||||
| call店舗QR設定認証設定全削除({ | |||||
| shop_id: shop.shop_id, | |||||
| parking_management_code: tmpDeleteTargetParkingMangementCode, | |||||
| }); | |||||
| } | |||||
| }, [isAgree, tmpDeleteTargetParkingMangementCode, shop]); | |||||
| return ( | |||||
| <Card sx={{ p: 2 }} elevation={1}> | |||||
| <Stack spacing={2}> | |||||
| <Typography variant="h6">駐車場ごと設定</Typography> | |||||
| <Box> | |||||
| {Object.keys(駐車場ごと設定).map((parkingManagementCode) => { | |||||
| const setting = 駐車場ごと設定[parkingManagementCode]; | |||||
| return ( | |||||
| <RowData | |||||
| key={parkingManagementCode} | |||||
| settings={setting} | |||||
| deleteParkingSetting={deleteParkingSetting} | |||||
| /> | |||||
| ); | |||||
| })} | |||||
| {Object.keys(駐車場ごと設定).length === 0 && ( | |||||
| <Typography>データなし</Typography> | |||||
| )} | |||||
| </Box> | |||||
| </Stack> | |||||
| {dialog} | |||||
| </Card> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,76 @@ | |||||
| import { Button, Grid, Typography } from "@mui/material"; | |||||
| import { サービス券マスタ } from "api/parking"; | |||||
| import { QRサービス券認証設定, 店舗QR設定認証設定削除 } from "api/shop"; | |||||
| import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import { useContext, useMemo } from "react"; | |||||
| import { sprintf } from "sprintf-js"; | |||||
| type DiscountTicketProps = { | |||||
| setting: QRサービス券認証設定; | |||||
| discountTickets: サービス券マスタ[]; | |||||
| }; | |||||
| export default function Page({ | |||||
| setting, | |||||
| discountTickets, | |||||
| }: DiscountTicketProps) { | |||||
| const { shop, fetch } = useContext(店舗詳細Context); | |||||
| const { success, error } = useSnackbarCustom(); | |||||
| const { callAPI: call店舗QR設定認証設定削除 } = useAPICall({ | |||||
| apiMethod: 店舗QR設定認証設定削除, | |||||
| backDrop: true, | |||||
| onSuccess: () => { | |||||
| fetch(); | |||||
| success("削除しました"); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const discountTikcetName = useMemo(() => { | |||||
| const target = discountTickets.find((ele) => { | |||||
| return ele.discount_ticket_code === setting.discount_ticket_code; | |||||
| }); | |||||
| return sprintf( | |||||
| "%s(%d)", | |||||
| target?.ticket_name ?? "", | |||||
| setting.discount_ticket_code | |||||
| ); | |||||
| }, [discountTickets, setting]); | |||||
| const handleRemove = () => { | |||||
| if (shop === null) return; | |||||
| call店舗QR設定認証設定削除({ | |||||
| shop_id: String(shop.shop_id), | |||||
| parking_management_code: setting.parking_management_code, | |||||
| discount_ticket_code: String(setting.discount_ticket_code), | |||||
| }); | |||||
| }; | |||||
| if (setting.discount_ticket_code === null) { | |||||
| return null; | |||||
| } | |||||
| return ( | |||||
| <Grid | |||||
| container | |||||
| sx={{ | |||||
| borderBottom: "solid 0.5px", | |||||
| borderBottomColor: "#a9a9a9", | |||||
| }} | |||||
| > | |||||
| <Grid item xs={9}> | |||||
| <Typography>{discountTikcetName}</Typography> | |||||
| </Grid> | |||||
| <Grid item xs={3}> | |||||
| <Button color="error" onClick={handleRemove}> | |||||
| 削除 | |||||
| </Button> | |||||
| </Grid> | |||||
| </Grid> | |||||
| ); | |||||
| } | |||||
| @@ -0,0 +1,205 @@ | |||||
| import DeleteForeverIcon from "@mui/icons-material/DeleteForever"; | |||||
| import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; | |||||
| import { | |||||
| Accordion, | |||||
| AccordionDetails, | |||||
| AccordionSummary, | |||||
| Box, | |||||
| Button, | |||||
| Grid, | |||||
| IconButton, | |||||
| Stack, | |||||
| Typography, | |||||
| } from "@mui/material"; | |||||
| import { サービス券マスタ, サービス券マスタ一覧取得 } from "api/parking"; | |||||
| import { | |||||
| QRサービス券認証設定, | |||||
| 店舗QR設定認証設定更新, | |||||
| 店舗QR設定認証設定追加, | |||||
| } from "api/shop"; | |||||
| import { FormProvider, RHFTextField } from "components/hook-form"; | |||||
| import RHFAutoComplete, { | |||||
| AutoCompleteOption, | |||||
| AutoCompleteOptionType, | |||||
| getValue, | |||||
| } from "components/hook-form/RHFAutoComplete"; | |||||
| import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; | |||||
| import useAPICall from "hooks/useAPICall"; | |||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | |||||
| import { useContext, useEffect, useMemo, useState } from "react"; | |||||
| import { useForm } from "react-hook-form"; | |||||
| import { sprintf } from "sprintf-js"; | |||||
| import DiscountTicket from "./サービス券"; | |||||
| type FormProps = { | |||||
| shop_no: string; | |||||
| discount_ticket_code: AutoCompleteOptionType; | |||||
| }; | |||||
| type RowProps = { | |||||
| settings: QRサービス券認証設定[]; | |||||
| deleteParkingSetting: (parkingManagementCode: string) => void; | |||||
| }; | |||||
| export default function Page({ settings, deleteParkingSetting }: RowProps) { | |||||
| const { shop, fetch } = useContext(店舗詳細Context); | |||||
| const { success, error } = useSnackbarCustom(); | |||||
| const { parking_name, parking_management_code, shop_no } = settings[0]; | |||||
| const [サービス券マスタ, setサービス券マスタ] = useState<サービス券マスタ[]>( | |||||
| [] | |||||
| ); | |||||
| const form = useForm<FormProps>({ | |||||
| defaultValues: { | |||||
| shop_no: String(shop_no), | |||||
| discount_ticket_code: null, | |||||
| }, | |||||
| }); | |||||
| const { callAPI: callサービス券マスタ一覧取得 } = useAPICall({ | |||||
| apiMethod: サービス券マスタ一覧取得, | |||||
| onSuccess: ({ data }) => { | |||||
| setサービス券マスタ(data.list); | |||||
| }, | |||||
| }); | |||||
| const { callAPI: call店舗QR設定認証設定更新 } = useAPICall({ | |||||
| apiMethod: 店舗QR設定認証設定更新, | |||||
| form, | |||||
| backDrop: true, | |||||
| onSuccess: () => { | |||||
| fetch(); | |||||
| success("変更しました"); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const { callAPI: call店舗QR設定認証設定追加 } = useAPICall({ | |||||
| apiMethod: 店舗QR設定認証設定追加, | |||||
| form, | |||||
| backDrop: true, | |||||
| onSuccess: () => { | |||||
| fetch(); | |||||
| success("追加しました"); | |||||
| form.setValue("discount_ticket_code", null); | |||||
| }, | |||||
| onFailed: () => { | |||||
| error("失敗しました"); | |||||
| }, | |||||
| }); | |||||
| const options: AutoCompleteOption[] = useMemo(() => { | |||||
| return サービス券マスタ | |||||
| .filter( | |||||
| (ele) => | |||||
| !settings.find( | |||||
| (s) => s.discount_ticket_code === ele.discount_ticket_code | |||||
| ) | |||||
| ) | |||||
| .map((ele) => ({ | |||||
| label: sprintf("%s(%d)", ele.ticket_name, ele.discount_ticket_code), | |||||
| value: String(ele.discount_ticket_code), | |||||
| })); | |||||
| }, [サービス券マスタ, settings]); | |||||
| const handleUpdate = () => { | |||||
| if (shop === null) return; | |||||
| call店舗QR設定認証設定更新({ | |||||
| ...form.getValues(), | |||||
| shop_id: String(shop.shop_id), | |||||
| parking_management_code, | |||||
| }); | |||||
| }; | |||||
| const handleAdd = () => { | |||||
| if (shop === null) return; | |||||
| call店舗QR設定認証設定追加({ | |||||
| shop_id: String(shop.shop_id), | |||||
| parking_management_code, | |||||
| discount_ticket_code: getValue(form.getValues("discount_ticket_code")), | |||||
| }); | |||||
| }; | |||||
| const handleDelete = () => { | |||||
| deleteParkingSetting(parking_management_code); | |||||
| }; | |||||
| useEffect(() => { | |||||
| callサービス券マスタ一覧取得({ | |||||
| parking_management_code: parking_management_code, | |||||
| }); | |||||
| }, []); | |||||
| return ( | |||||
| <FormProvider methods={form}> | |||||
| <Accordion square={true}> | |||||
| <AccordionSummary | |||||
| expandIcon={<ExpandMoreIcon />} | |||||
| aria-controls="panel2-content" | |||||
| id="panel2-header" | |||||
| sx={{ backgroundColor: "#b0e0e6" }} | |||||
| > | |||||
| {parking_name} | |||||
| <IconButton | |||||
| size="small" | |||||
| sx={{ marginLeft: "auto" }} | |||||
| onClick={(event) => { | |||||
| event.stopPropagation(); | |||||
| handleDelete(); | |||||
| }} | |||||
| > | |||||
| <DeleteForeverIcon /> | |||||
| </IconButton> | |||||
| </AccordionSummary> | |||||
| <AccordionDetails> | |||||
| <Grid container columnSpacing={2}> | |||||
| <Grid item xs={7}> | |||||
| <Stack spacing={1}> | |||||
| <Box> | |||||
| <Typography>店舗コード</Typography> | |||||
| <Grid container columnSpacing={1}> | |||||
| <Grid item xs={8}> | |||||
| <RHFTextField name="shop_no" /> | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Button onClick={handleUpdate}>更新</Button> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </Box> | |||||
| <Box> | |||||
| <Typography>サービス券コード</Typography> | |||||
| <Grid container columnSpacing={1}> | |||||
| <Grid item xs={8}> | |||||
| <RHFAutoComplete | |||||
| size="small" | |||||
| name="discount_ticket_code" | |||||
| options={options} | |||||
| /> | |||||
| </Grid> | |||||
| <Grid item xs={4}> | |||||
| <Button onClick={handleAdd}>追加</Button> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </Box> | |||||
| </Stack> | |||||
| </Grid> | |||||
| <Grid item xs={5}> | |||||
| <Stack> | |||||
| {settings | |||||
| .filter((ele) => ele.discount_ticket_code !== null) | |||||
| .map((ele, index) => ( | |||||
| <DiscountTicket | |||||
| key={index} | |||||
| setting={ele} | |||||
| discountTickets={サービス券マスタ} | |||||
| /> | |||||
| ))} | |||||
| </Stack> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </AccordionDetails> | |||||
| </Accordion> | |||||
| </FormProvider> | |||||
| ); | |||||
| } | |||||
| @@ -1,49 +1,57 @@ | |||||
| import { yupResolver } from "@hookform/resolvers/yup"; | import { yupResolver } from "@hookform/resolvers/yup"; | ||||
| import { Box, Button, Card, Grid, Stack, Typography } from "@mui/material"; | import { Box, Button, Card, Grid, Stack, Typography } from "@mui/material"; | ||||
| import { QRサービス券駐車場グループ駐車場追加登録 } from "api/qr-service"; | |||||
| import { FormProvider, RHFAutoComplete } from "components/hook-form"; | |||||
| import { 駐車場マスタ } from "api/parking"; | |||||
| import { 店舗QR設定認証設定新規登録 } from "api/shop"; | |||||
| import { | |||||
| FormProvider, | |||||
| RHFAutoComplete, | |||||
| RHFTextField, | |||||
| } from "components/hook-form"; | |||||
| import { | import { | ||||
| AutoCompleteOption, | AutoCompleteOption, | ||||
| AutoCompleteOptionType, | AutoCompleteOptionType, | ||||
| getValue, | getValue, | ||||
| } from "components/hook-form/RHFAutoComplete"; | } from "components/hook-form/RHFAutoComplete"; | ||||
| import StackRow from "components/stack/StackRow"; | import StackRow from "components/stack/StackRow"; | ||||
| import { QRサービス券駐車場グループ管理Context } from "contexts/page/dashboard/parking/QRサービス券駐車場グループ管理Context"; | |||||
| import { 店舗詳細Context } from "contexts/page/dashboard/shop/店舗詳細Context"; | |||||
| import useAPICall from "hooks/useAPICall"; | import useAPICall from "hooks/useAPICall"; | ||||
| import useSnackbarCustom from "hooks/useSnackbarCustom"; | import useSnackbarCustom from "hooks/useSnackbarCustom"; | ||||
| import { useContext, useMemo } from "react"; | |||||
| import { useContext, useEffect, useMemo, useState } from "react"; | |||||
| import { useForm } from "react-hook-form"; | import { useForm } from "react-hook-form"; | ||||
| import { object } from "yup"; | |||||
| import { number, object } from "yup"; | |||||
| type FormProps = { | type FormProps = { | ||||
| parking_management_code: AutoCompleteOptionType; | parking_management_code: AutoCompleteOptionType; | ||||
| shop_no: string; | |||||
| }; | }; | ||||
| export default function 駐車場追加() { | export default function 駐車場追加() { | ||||
| const { fetch, selectedGroup, parkings } = useContext( | |||||
| QRサービス券駐車場グループ管理Context | |||||
| ); | |||||
| const { shop, fetch, moveToMain, certificationSetting, parkings } = | |||||
| useContext(店舗詳細Context); | |||||
| const { success, error } = useSnackbarCustom(); | const { success, error } = useSnackbarCustom(); | ||||
| const form = useForm<FormProps>({ | const form = useForm<FormProps>({ | ||||
| defaultValues: { | defaultValues: { | ||||
| parking_management_code: null, | parking_management_code: null, | ||||
| shop_no: "", | |||||
| }, | }, | ||||
| resolver: yupResolver( | resolver: yupResolver( | ||||
| object().shape({ | object().shape({ | ||||
| parking_management_code: object().required("必須項目です"), | parking_management_code: object().required("必須項目です"), | ||||
| shop_no: number().typeError("数値を入力してください"), | |||||
| }) | }) | ||||
| ), | ), | ||||
| }); | }); | ||||
| const { callAPI: callQRサービス券駐車場グループ駐車場追加登録 } = useAPICall({ | |||||
| apiMethod: QRサービス券駐車場グループ駐車場追加登録, | |||||
| const { callAPI: call店舗QR設定認証設定新規登録 } = useAPICall({ | |||||
| apiMethod: 店舗QR設定認証設定新規登録, | |||||
| backDrop: true, | backDrop: true, | ||||
| form, | form, | ||||
| onSuccess: () => { | onSuccess: () => { | ||||
| success("追加しました"); | |||||
| success("登録しました"); | |||||
| fetch(); | fetch(); | ||||
| form.setValue("parking_management_code", null); | form.setValue("parking_management_code", null); | ||||
| form.setValue("shop_no", ""); | |||||
| }, | }, | ||||
| onFailed: () => { | onFailed: () => { | ||||
| error("失敗しました"); | error("失敗しました"); | ||||
| @@ -54,7 +62,7 @@ export default function 駐車場追加() { | |||||
| return parkings | return parkings | ||||
| .filter( | .filter( | ||||
| (p) => | (p) => | ||||
| !selectedGroup?.parkings.find( | |||||
| !certificationSetting.find( | |||||
| (ele) => ele.parking_management_code === p.parking_management_code | (ele) => ele.parking_management_code === p.parking_management_code | ||||
| ) | ) | ||||
| ) | ) | ||||
| @@ -62,14 +70,14 @@ export default function 駐車場追加() { | |||||
| label: p.parking_name, | label: p.parking_name, | ||||
| value: p.parking_management_code, | value: p.parking_management_code, | ||||
| })); | })); | ||||
| }, [parkings, selectedGroup]); | |||||
| }, [parkings, certificationSetting]); | |||||
| const handleSubmit = (data: FormProps) => { | const handleSubmit = (data: FormProps) => { | ||||
| if (selectedGroup === null) return; | |||||
| const parkingManagementCode = getValue(data.parking_management_code); | |||||
| callQRサービス券駐車場グループ駐車場追加登録({ | |||||
| id: selectedGroup.id, | |||||
| parking_management_code: parkingManagementCode, | |||||
| if (shop === null) return; | |||||
| call店舗QR設定認証設定新規登録({ | |||||
| ...data, | |||||
| parking_management_code: getValue(data.parking_management_code), | |||||
| shop_id: shop?.shop_id, | |||||
| }); | }); | ||||
| }; | }; | ||||
| @@ -80,7 +88,7 @@ export default function 駐車場追加() { | |||||
| <Stack spacing={2}> | <Stack spacing={2}> | ||||
| <Typography variant="h6">駐車場追加</Typography> | <Typography variant="h6">駐車場追加</Typography> | ||||
| <StackRow> | <StackRow> | ||||
| <Grid container columnGap={2}> | |||||
| <Grid container columnSpacing={2}> | |||||
| <Grid item xs={12} md={6}> | <Grid item xs={12} md={6}> | ||||
| <Typography>駐車場</Typography> | <Typography>駐車場</Typography> | ||||
| <StackRow> | <StackRow> | ||||
| @@ -93,6 +101,16 @@ export default function 駐車場追加() { | |||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| </StackRow> | </StackRow> | ||||
| <StackRow> | |||||
| <Grid container columnSpacing={2}> | |||||
| <Grid item xs={12} md={6}> | |||||
| <Typography>店舗番号</Typography> | |||||
| <StackRow> | |||||
| <RHFTextField type="number" name="shop_no" /> | |||||
| </StackRow> | |||||
| </Grid> | |||||
| </Grid> | |||||
| </StackRow> | |||||
| <StackRow> | <StackRow> | ||||
| <Button type="submit" variant="contained"> | <Button type="submit" variant="contained"> | ||||
| 追加 | 追加 | ||||