From 4dfa95995c31cac3ebd458fb0c0ace4994bc7f47 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Thu, 28 Mar 2024 16:37:29 +0900 Subject: [PATCH] =?UTF-8?q?QR=E5=8F=96=E5=BE=97=E5=91=A8=E3=82=8A=E3=81=AE?= =?UTF-8?q?=E6=95=B4=E5=82=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/index.ts | 2 + src/api/login-user.ts | 33 +++- src/api/qr-service.ts | 33 ++++ src/api/url.ts | 3 + src/auth/route.ts | 6 +- src/contexts/AuthContext.tsx | 2 +- .../dashboard/shop/店舗詳細Context.tsx | 13 +- src/layouts/dashbord/navigator.tsx | 23 ++- .../login-user/店舗/一覧/SearchBox.tsx | 85 ++++++++++ .../login-user/店舗/一覧/TableBox.tsx | 100 ++++++++++++ .../login-user/店舗/一覧/index.tsx | 38 +++++ .../login-user/店舗/新規登録/index.tsx | 149 ++++++++++++++++++ .../SearchBox.tsx | 7 +- .../TableBox.tsx | 6 +- .../index.tsx | 4 +- .../サービス券発行用QRコード.tsx | 103 ++++++++++-- .../店舗詳細/QR取得設定/index.tsx | 6 +- .../QR認証設定/駐車場一覧/index.tsx | 2 +- .../QR認証設定/駐車場追加.tsx | 1 + .../QRサービス券発行申請.tsx | 2 +- src/routes/path.ts | 9 +- src/routes/sub/dashboard.tsx | 35 +++- 22 files changed, 609 insertions(+), 53 deletions(-) create mode 100644 src/pages/dashboard/login-user/店舗/一覧/SearchBox.tsx create mode 100644 src/pages/dashboard/login-user/店舗/一覧/TableBox.tsx create mode 100644 src/pages/dashboard/login-user/店舗/一覧/index.tsx create mode 100644 src/pages/dashboard/login-user/店舗/新規登録/index.tsx diff --git a/src/api/index.ts b/src/api/index.ts index 71515be..233ecb6 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -51,6 +51,8 @@ export const ApiId = { QRサービス券駐車場グループ新規登録: id++, QRサービス券駐車場グループ駐車場追加登録: id++, QRサービス券駐車場グループ駐車場削除登録: id++, + QRサービス券取得用トークン取得: id++, + QRサービス券取得用トークンリフレッシュ: id++, QRサービス券取得: id++, } as const; export type ApiId = (typeof ApiId)[keyof typeof ApiId]; diff --git a/src/api/login-user.ts b/src/api/login-user.ts index 96b34e4..e4bfebe 100644 --- a/src/api/login-user.ts +++ b/src/api/login-user.ts @@ -1,7 +1,7 @@ import { APICommonResponse, ApiId, HttpMethod, makeParam, request } from "api"; import { getUrl } from "./url"; -export type 運営会社ログインユーザ = { +export type 顧客ログインユーザ = { id: string; name: string; email: string; @@ -9,6 +9,14 @@ export type 運営会社ログインユーザ = { customer_name: string; }; +export type 店舗ログインユーザ = { + id: string; + name: string; + email: string; + shop_id: string; + shop_name: string; +}; + // -------顧客ログインユーザ新規登録--------------- export type 顧客ログインユーザ新規登録Request = { name: string; @@ -62,7 +70,7 @@ export type 顧客ログインユーザ一覧取得Request = { }; export type 顧客ログインユーザ一覧取得Response = { data: { - list: 運営会社ログインユーザ[]; + list: 顧客ログインユーザ[]; }; } & APICommonResponse; export const 顧客ログインユーザ一覧取得 = async ( @@ -75,3 +83,24 @@ export const 顧客ログインユーザ一覧取得 = async ( }); return res; }; + +// -------店舗ログインユーザ一覧取得--------------- +export type 店舗ログインユーザ一覧取得Request = { + email?: string; + name?: 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; +}; diff --git a/src/api/qr-service.ts b/src/api/qr-service.ts index 1afa32f..f3e4364 100644 --- a/src/api/qr-service.ts +++ b/src/api/qr-service.ts @@ -102,3 +102,36 @@ export const QRサービス券駐車場グループ駐車場削除登録 = async }); return res; }; + +// -------QRサービス券取得用トークン取得--------------- +export type QRサービス券取得用トークン取得Request = {}; +export type QRサービス券取得用トークン取得Response = { + data: { + token: string; + }; +} & APICommonResponse; +export const QRサービス券取得用トークン取得 = async ( + param: QRサービス券取得用トークン取得Request +) => { + const res = await request({ + url: getUrl(ApiId.QRサービス券取得用トークン取得), + method: HttpMethod.GET, + data: makeParam(param), + }); + return res; +}; + +// -------QRサービス券取得用トークンリフレッシュ--------------- +export type QRサービス券取得用トークンリフレッシュRequest = {}; +export type QRサービス券取得用トークンリフレッシュResponse = + {} & APICommonResponse; +export const QRサービス券取得用トークンリフレッシュ = async ( + param: QRサービス券取得用トークンリフレッシュRequest +) => { + const res = await request({ + url: getUrl(ApiId.QRサービス券取得用トークンリフレッシュ), + method: HttpMethod.POST, + data: makeParam(param), + }); + return res; +}; diff --git a/src/api/url.ts b/src/api/url.ts index ea46664..45c08b8 100644 --- a/src/api/url.ts +++ b/src/api/url.ts @@ -49,6 +49,9 @@ const urls = { "qr-service/parking-group/parking/add", [A.QRサービス券駐車場グループ駐車場削除登録]: "qr-service/parking-group/parking/remove", + [A.QRサービス券取得用トークン取得]: "qr-service/acquisition/token", + [A.QRサービス券取得用トークンリフレッシュ]: + "qr-service/acquisition/token/refresh", [A.QRサービス券取得]: "qr-service/get-ticket", }; diff --git a/src/auth/route.ts b/src/auth/route.ts index 56ae90b..ca33e13 100644 --- a/src/auth/route.ts +++ b/src/auth/route.ts @@ -1,9 +1,9 @@ import { PageID as P } from "pages"; import { UserRole } from "./UserRole"; -const 共通ルート = [P.LOGIN, P.LOGOUT]; -const 認証後共通ルート = [P.DASHBOARD_ENPTY, P.DASHBOARD_OVERVIEW]; -const 管理者顧客共通ルート = [P.成り代わり終了]; +const 共通ルート: P[] = [P.LOGIN, P.LOGOUT, P.成り代わり終了]; +const 認証後共通ルート: P[] = [P.DASHBOARD_ENPTY, P.DASHBOARD_OVERVIEW]; +const 管理者顧客共通ルート: P[] = []; const 認可別許可ルート: { [route: string]: P[]; diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 33ce84f..63c1e92 100644 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -176,7 +176,6 @@ function AuthContextProvider({ children }: Props) { const cacheClear = () => { 駐車場マスタストア.clear(); - 駐車場マスタストア.clear(); }; const login = async (email: string, password: string) => { @@ -193,6 +192,7 @@ function AuthContextProvider({ children }: Props) { user_id, }); navigateWhenChanged(getPath(PageID.DASHBOARD_OVERVIEW)); + cacheClear(); }; const switchShopRole = async (user_id: string) => { await call店舗成り代わり開始({ user_id }); diff --git a/src/contexts/page/dashboard/shop/店舗詳細Context.tsx b/src/contexts/page/dashboard/shop/店舗詳細Context.tsx index de6fd50..ccfd0bb 100644 --- a/src/contexts/page/dashboard/shop/店舗詳細Context.tsx +++ b/src/contexts/page/dashboard/shop/店舗詳細Context.tsx @@ -20,8 +20,8 @@ import 駐車場マスタストア from "storage/cache/駐車場マスタ"; type Context = { shop: 店舗 | null; - certificationSetting: QRサービス券認証設定[]; - acquisitionSetting: QRサービス券取得設定 | null; + certificationSetting: QRサービス券認証設定[] | undefined; + acquisitionSetting: QRサービス券取得設定 | null | undefined; parkings: 駐車場マスタ[]; fetch: () => Promise; moveToMain: VoidFunction; @@ -43,10 +43,11 @@ function 店舗詳細ContextProvider({ children }: Props) { const [shop, setShop] = useState<店舗 | null>(null); const [parkings, setParkings] = useState<駐車場マスタ[]>([]); const [certificationSetting, setCertificationSetting] = useState< - QRサービス券認証設定[] - >([]); - const [acquisitionSetting, setAcquisitionSetting] = - useState(null); + QRサービス券認証設定[] | undefined + >(undefined); + const [acquisitionSetting, setAcquisitionSetting] = useState< + QRサービス券取得設定 | null | undefined + >(undefined); const { success, error } = useSnackbarCustom(); const { navigateWhenChanged } = useNavigateCustom(); diff --git a/src/layouts/dashbord/navigator.tsx b/src/layouts/dashbord/navigator.tsx index adf15f5..bb314ff 100644 --- a/src/layouts/dashbord/navigator.tsx +++ b/src/layouts/dashbord/navigator.tsx @@ -90,20 +90,30 @@ export default function Navigator(props: DrawerProps) { icon: , id: PageID.ログインユーザ_顧客新規登録, }, + { + label: "店舗一覧", + icon: , + id: PageID.ログインユーザ_店舗一覧, + }, + { + label: "店舗新規登録", + icon: , + id: PageID.ログインユーザ_店舗新規登録, + }, ], }, { label: "店舗管理", children: [ { - label: "店舗新規登録", + label: "店舗一覧", icon: , - id: PageID.店舗新規登録, + id: PageID.店舗一覧, }, { - label: "店舗一覧", + label: "店舗新規登録", icon: , - id: PageID.店舗一覧, + id: PageID.店舗新規登録, }, ], }, @@ -129,6 +139,11 @@ export default function Navigator(props: DrawerProps) { { label: "QRサービス券", children: [ + { + label: "サービス券発行", + icon: , + id: PageID.サービス券発行用QRコード, + }, { label: "利用履歴", icon: , diff --git a/src/pages/dashboard/login-user/店舗/一覧/SearchBox.tsx b/src/pages/dashboard/login-user/店舗/一覧/SearchBox.tsx new file mode 100644 index 0000000..dc4837b --- /dev/null +++ b/src/pages/dashboard/login-user/店舗/一覧/SearchBox.tsx @@ -0,0 +1,85 @@ +import { Box, Grid, Stack, Typography } from "@mui/material"; +import { Dictionary } from "@types"; +import { 店舗ログインユーザ, 店舗ログインユーザ一覧取得 } from "api/login-user"; +import { FormProvider, RHFTextField } from "components/hook-form"; +import useAPICall from "hooks/useAPICall"; +import useSearchConditionContext from "hooks/useSearchConditionContext"; +import { UseTableReturn } from "hooks/useTable"; +import { isEqual } from "lodash"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; + +type FormProps = { + name: string; + email: string; +}; + +type CommonProps = { + table: UseTableReturn<店舗ログインユーザ>; +}; +export default function SearchBox({ table }: CommonProps) { + const [lastSendSearchCondition, setLastSendSearchCondition] = + useState({ default: false }); + const { condition, initialized, get, addCondition } = + useSearchConditionContext(); + const form = useForm({ + defaultValues: { + name: "", + email: "", + }, + }); + + const { callAPI: call店舗ログインユーザ一覧取得, makeSendData } = useAPICall({ + apiMethod: 店舗ログインユーザ一覧取得, + form, + backDrop: true, + onSuccess: ({ data }) => { + table.setRowData(data.list); + }, + }); + + const handleBlur = () => { + addCondition(form.getValues()); + }; + const handleSubmit = async (data: FormProps) => { + addCondition(data); + }; + + const fetch = async (data: Dictionary) => { + const sendData = makeSendData(data); + if (!isEqual(sendData, lastSendSearchCondition)) { + setLastSendSearchCondition(sendData); + call店舗ログインユーザ一覧取得(sendData); + } + }; + + // 初期値設定 + useEffect(() => { + if (initialized) { + fetch(condition); + form.setValue("name", get("name")); + form.setValue("email", get("email")); + } + }, [condition, initialized]); + + return ( + + + + + + 名前 + + + + + + Email + + + + + + + ); +} diff --git a/src/pages/dashboard/login-user/店舗/一覧/TableBox.tsx b/src/pages/dashboard/login-user/店舗/一覧/TableBox.tsx new file mode 100644 index 0000000..0d72c71 --- /dev/null +++ b/src/pages/dashboard/login-user/店舗/一覧/TableBox.tsx @@ -0,0 +1,100 @@ +import { + Box, + Table, + TableBody, + TableCell, + TableContainer, + TablePagination, + TableRow, +} from "@mui/material"; +import { 店舗ログインユーザ } from "api/login-user"; +import TableHeadCustom, { + HeadLabelProps, +} from "components/table/TableHeadCustom"; +import useAuth from "hooks/useAuth"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { UseTableReturn } from "hooks/useTable"; + +type CommonProps = { + table: UseTableReturn<店舗ログインユーザ>; +}; +export default function TableBox({ table }: CommonProps) { + const TABLE_HEAD: HeadLabelProps[] = [ + { id: "name", label: "名前", align: "left", needSort: false }, + { id: "email", label: "Email", align: "left", needSort: false }, + { id: "shop_name", label: "店舗名", align: "left", needSort: false }, + ]; + const { + order, + page, + sort, + rowsPerPage, + fetched, + fillteredRow, + isNotFound, + dataLength, + // + onSort, + onChangePage, + onChangeRowsPerPage, + // + setRowData, + // + ROWS_PER_PAGES, + } = table; + + return ( + <> + + + + + + {fillteredRow.map((row, index) => ( + + ))} + +
+
+ + + + + + ); +} + +type RowProps = { + data: 店舗ログインユーザ; +}; +function Row({ data }: RowProps) { + const { switchShopRole } = useAuth(); + const { info } = useSnackbarCustom(); + const handleClick = () => { + switchShopRole(data.id); + info("成り代わり開始しました"); + }; + + return ( + + {data.name} + {data.email} + {data.shop_name} + + ); +} diff --git a/src/pages/dashboard/login-user/店舗/一覧/index.tsx b/src/pages/dashboard/login-user/店舗/一覧/index.tsx new file mode 100644 index 0000000..95548f0 --- /dev/null +++ b/src/pages/dashboard/login-user/店舗/一覧/index.tsx @@ -0,0 +1,38 @@ +import { Box } from "@mui/material"; +import { 店舗ログインユーザ } from "api/login-user"; +import { SearchConditionContextProvider } from "contexts/SearchConditionContext"; +import useDashboard from "hooks/useDashBoard"; +import useTable from "hooks/useTable"; +import { PageID, TabID } from "pages"; +import { useEffect } from "react"; +import SearchBox from "./SearchBox"; +import TableBox from "./TableBox"; + +export default function Main() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.ログインユーザ_店舗一覧, + TabID.NONE + ); + + useEffect(() => { + setHeaderTitle("ログインユーザ一覧"); + setTabs(null); + }, []); + + return ( + + + + ); +} + +function Page() { + const table = useTable<店舗ログインユーザ>(); + + return ( + + + + + ); +} diff --git a/src/pages/dashboard/login-user/店舗/新規登録/index.tsx b/src/pages/dashboard/login-user/店舗/新規登録/index.tsx new file mode 100644 index 0000000..9ab1856 --- /dev/null +++ b/src/pages/dashboard/login-user/店舗/新規登録/index.tsx @@ -0,0 +1,149 @@ +import { yupResolver } from "@hookform/resolvers/yup"; +import { Box, Button, Stack, Typography } from "@mui/material"; +import { 店舗ログインユーザ新規登録 } from "api/login-user"; +import { 店舗, 店舗一覧取得 } from "api/shop"; +import { + FormProvider, + RHFAutoComplete, + RHFTextField, +} from "components/hook-form"; +import { + AutoCompleteOption, + AutoCompleteOptionType, + getValue, +} from "components/hook-form/RHFAutoComplete"; +import StackRow from "components/stack/StackRow"; +import useAPICall from "hooks/useAPICall"; +import useDashboard from "hooks/useDashBoard"; +import useNavigateCustom from "hooks/useNavigateCustom"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; +import { PageID, TabID } from "pages"; +import { useEffect, useMemo, useState } from "react"; +import { useForm } from "react-hook-form"; +import { getPath } from "routes/path"; +import { object, string } from "yup"; + +type FormProps = { + name: string; + email: string; + password: string; + password_retype: string; + shop_id: AutoCompleteOptionType; +}; + +export default function Main() { + const { setHeaderTitle, setTabs } = useDashboard( + PageID.ログインユーザ_店舗新規登録, + TabID.NONE + ); + + const { success, error } = useSnackbarCustom(); + const { navigateWhenChanged } = useNavigateCustom(); + + const [shops, setShops] = useState<店舗[]>([]); + + const shopOptions: AutoCompleteOption[] = useMemo(() => { + return shops.map((data) => { + return { + label: data.name, + value: data.shop_id, + }; + }); + }, [shops]); + + const form = useForm({ + defaultValues: { + name: "", + email: "", + password: "", + password_retype: "", + shop_id: "", + }, + resolver: yupResolver( + object().shape({ + name: string().required("必須項目です"), + email: string().required("必須項目です"), + password: string().required("必須項目です"), + password_retype: string() + .required("必須項目です") + .test("retype", "入力が一致しません", function (value) { + return this.parent.password === value; + }), + shop_id: object().required("必須項目です"), + }) + ), + }); + + const { callAPI: call店舗ログインユーザ新規登録 } = useAPICall({ + apiMethod: 店舗ログインユーザ新規登録, + form, + backDrop: true, + onSuccess: ({ data }, sendData) => { + success("登録しました"); + navigateWhenChanged( + getPath(PageID.ログインユーザ_店舗一覧), + new URLSearchParams({ email: sendData.email }) + ); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + + const { callAPI: call店舗一覧取得 } = useAPICall({ + apiMethod: 店舗一覧取得, + onSuccess: ({ data }) => { + setShops(data.list); + }, + }); + + const handleSubmit = (data: FormProps) => { + call店舗ログインユーザ新規登録({ + ...data, + shop_id: getValue(data.shop_id), + }); + }; + + useEffect(() => { + setHeaderTitle("ログインユーザ登録"); + setTabs(null); + + call店舗一覧取得({}); + }, []); + + return ( + + + + + 名称 + + + + Email + + + + パスワード + + + + パスワード(再入力) + + + + 店舗 + + + + + + + + + ); +} diff --git a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/SearchBox.tsx b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/SearchBox.tsx index be4ceb3..69fedba 100644 --- a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/SearchBox.tsx +++ b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/SearchBox.tsx @@ -1,9 +1,6 @@ import { Box, Grid, Stack, Typography } from "@mui/material"; import { Dictionary } from "@types"; -import { - 運営会社ログインユーザ, - 顧客ログインユーザ一覧取得, -} from "api/login-user"; +import { 顧客ログインユーザ, 顧客ログインユーザ一覧取得 } from "api/login-user"; import { FormProvider, RHFTextField } from "components/hook-form"; import useAPICall from "hooks/useAPICall"; import useSearchConditionContext from "hooks/useSearchConditionContext"; @@ -18,7 +15,7 @@ type FormProps = { }; type CommonProps = { - table: UseTableReturn<運営会社ログインユーザ>; + table: UseTableReturn<顧客ログインユーザ>; }; export default function SearchBox({ table }: CommonProps) { const [lastSendSearchCondition, setLastSendSearchCondition] = diff --git a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx index d7b60b5..22750e6 100644 --- a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx +++ b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/TableBox.tsx @@ -7,7 +7,7 @@ import { TablePagination, TableRow, } from "@mui/material"; -import { 運営会社ログインユーザ } from "api/login-user"; +import { 顧客ログインユーザ } from "api/login-user"; import TableHeadCustom, { HeadLabelProps, } from "components/table/TableHeadCustom"; @@ -16,7 +16,7 @@ import useSnackbarCustom from "hooks/useSnackbarCustom"; import { UseTableReturn } from "hooks/useTable"; type CommonProps = { - table: UseTableReturn<運営会社ログインユーザ>; + table: UseTableReturn<顧客ログインユーザ>; }; export default function TableBox({ table }: CommonProps) { const TABLE_HEAD: HeadLabelProps[] = [ @@ -80,7 +80,7 @@ export default function TableBox({ table }: CommonProps) { } type RowProps = { - data: 運営会社ログインユーザ; + data: 顧客ログインユーザ; }; function Row({ data }: RowProps) { const { switchCustomerRole } = useAuth(); diff --git a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/index.tsx b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/index.tsx index 57e34c1..fc5fdce 100644 --- a/src/pages/dashboard/login-user/顧客ログインユーザ一覧/index.tsx +++ b/src/pages/dashboard/login-user/顧客ログインユーザ一覧/index.tsx @@ -1,5 +1,5 @@ import { Box } from "@mui/material"; -import { 運営会社ログインユーザ } from "api/login-user"; +import { 顧客ログインユーザ } from "api/login-user"; import { SearchConditionContextProvider } from "contexts/SearchConditionContext"; import useDashboard from "hooks/useDashBoard"; import useTable from "hooks/useTable"; @@ -27,7 +27,7 @@ export default function 顧客一覧() { } function Page() { - const table = useTable<運営会社ログインユーザ>(); + const table = useTable<顧客ログインユーザ>(); return ( diff --git a/src/pages/dashboard/qr-service/サービス券発行用QRコード.tsx b/src/pages/dashboard/qr-service/サービス券発行用QRコード.tsx index 1f8a1ec..78fe6ed 100644 --- a/src/pages/dashboard/qr-service/サービス券発行用QRコード.tsx +++ b/src/pages/dashboard/qr-service/サービス券発行用QRコード.tsx @@ -1,9 +1,18 @@ import { Box, Button, Paper, Stack } from "@mui/material"; +import { HasChildren } from "@types"; +import { + QRサービス券取得用トークンリフレッシュ, + QRサービス券取得用トークン取得, +} from "api/qr-service"; +import useAPICall from "hooks/useAPICall"; +import useAuth from "hooks/useAuth"; import useDashboard from "hooks/useDashBoard"; -import useNavigateCustom from "hooks/useNavigateCustom"; +import { useDialog } from "hooks/useDialog"; +import useSnackbarCustom from "hooks/useSnackbarCustom"; import { PageID, TabID } from "pages"; import QRCode from "qrcode"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; +import { getFullPath, getPath } from "routes/path"; export default function サービス券発行用QRコード() { const { setHeaderTitle, setTabs } = useDashboard( @@ -12,23 +21,53 @@ export default function サービス券発行用QRコード() { ); const size = 200; - const url = "http://localhost:8080/dashboard/qr/generate"; + const { error } = useSnackbarCustom(); + const [token, setToken] = useState(""); + const [qr, setQr] = useState(""); - const { navigateWhenChanged } = useNavigateCustom(); + const { callAPI: callQRサービス券取得用トークン取得 } = useAPICall({ + apiMethod: QRサービス券取得用トークン取得, + backDrop: true, + onSuccess: ({ data }) => { + setToken(data.token); + }, + onFailed: () => { + error("QR表示失敗しました"); + }, + }); - const [qr, setQr] = useState(""); + const url = useMemo(() => { + if (!token) return ""; + return getFullPath(PageID.QRサービス券発行申請, { + query: { + token, + }, + }); + }, [token]); + + const fetch = () => { + callQRサービス券取得用トークン取得({}); + }; useEffect(() => { - QRCode.toDataURL(url, { - errorCorrectionLevel: "H", - }).then((data: string) => { - setQr(data); - }); - }, []); + if (url) { + console.log({ url }); + QRCode.toDataURL(url, { + errorCorrectionLevel: "H", + }).then((data: string) => { + setQr(data); + }); + } + }, [url]); useEffect(() => { setHeaderTitle("サービス券発行用QRコード"); }, [setHeaderTitle, setTabs]); + + useEffect(() => { + fetch(); + }, []); + return ( @@ -38,8 +77,7 @@ export default function サービス券発行用QRコード() { {!!qr && } - - + QRコードリフレッシュ @@ -47,3 +85,42 @@ export default function サービス券発行用QRコード() { ); } + +type RefreshButtonProps = { + fetch: VoidFunction; +} & HasChildren; +function RefreshButton({ fetch }: RefreshButtonProps) { + const {} = useAuth(); + const { success, error } = useSnackbarCustom(); + const { callAPI: callQRサービス券取得用トークンリフレッシュ } = useAPICall({ + apiMethod: QRサービス券取得用トークンリフレッシュ, + onSuccess: () => { + success("リフレッシュしました"); + fetch(); + }, + onFailed: () => { + error("失敗しました"); + }, + }); + + const { element, open, isAgree } = useDialog({ + message: "リフレッシュすると以前のQRコードが使えなくなります", + }); + + const handleClick = () => { + open(); + }; + + useEffect(() => { + if (isAgree) { + callQRサービス券取得用トークンリフレッシュ({}); + } + }, [isAgree]); + + return ( + <> + {element} + + + ); +} diff --git a/src/pages/dashboard/shop/店舗詳細/QR取得設定/index.tsx b/src/pages/dashboard/shop/店舗詳細/QR取得設定/index.tsx index 9dfa08e..e0a8eca 100644 --- a/src/pages/dashboard/shop/店舗詳細/QR取得設定/index.tsx +++ b/src/pages/dashboard/shop/店舗詳細/QR取得設定/index.tsx @@ -14,7 +14,11 @@ function Page() { const { shop, acquisitionSetting, certificationSetting } = useContext(店舗詳細Context); - if (!shop || !acquisitionSetting || !certificationSetting) { + if ( + !shop || + acquisitionSetting === undefined || + !certificationSetting === undefined + ) { return null; } diff --git a/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場一覧/index.tsx b/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場一覧/index.tsx index d14a264..5ea92c2 100644 --- a/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場一覧/index.tsx +++ b/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場一覧/index.tsx @@ -18,7 +18,7 @@ export default function Page() { const 駐車場ごと設定: 駐車場ごと設定 = useMemo(() => { const ret: 駐車場ごと設定 = {}; - certificationSetting.forEach((ele) => { + certificationSetting?.forEach((ele) => { if (has(ret, ele.parking_management_code)) { ret[ele.parking_management_code].push(ele); } else { diff --git a/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場追加.tsx b/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場追加.tsx index 61b8a56..8aa4372 100644 --- a/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場追加.tsx +++ b/src/pages/dashboard/shop/店舗詳細/QR認証設定/駐車場追加.tsx @@ -59,6 +59,7 @@ export default function 駐車場追加() { }); const options: AutoCompleteOption[] = useMemo(() => { + if (certificationSetting === undefined) return []; return parkings .filter( (p) => diff --git a/src/pages/qr-service/QRサービス券発行申請.tsx b/src/pages/qr-service/QRサービス券発行申請.tsx index f982099..0540995 100644 --- a/src/pages/qr-service/QRサービス券発行申請.tsx +++ b/src/pages/qr-service/QRサービス券発行申請.tsx @@ -56,7 +56,7 @@ export default function QRサービス券発行申請() { - 取得に失敗しました。店舗へお問合せ下さい。 + 無効なURLです。店舗へお問合せ下さい。 diff --git a/src/routes/path.ts b/src/routes/path.ts index 91bf81b..b4e0223 100644 --- a/src/routes/path.ts +++ b/src/routes/path.ts @@ -77,14 +77,14 @@ const PATHS = { [makePathKey(PageID.LOGOUT)]: "/logout", [makePathKey(PageID.成り代わり終了)]: "/role/switch/end", - [makePathKey(PageID.QRサービス券発行申請)]: "qr-service/acquitision/:token", + [makePathKey(PageID.QRサービス券発行申請)]: "/qr-service/acquitision/:token", // ダッシュボード---------------- ...PATHS_DASHBOARD, // その他 - [makePathKey(PageID.PAGE_403)]: "403", - [makePathKey(PageID.PAGE_404)]: "404", + [makePathKey(PageID.PAGE_403)]: "/403", + [makePathKey(PageID.PAGE_404)]: "/404", }; export type PathOption = { @@ -112,6 +112,9 @@ export function getPath(key: PathKey, option?: PathOption) { return path; } +export function getFullPath(key: PathKey, option?: PathOption) { + return window.location.origin + getPath(key, option); +} export function getListPagePath(key: PathKey, page: number): string { return getPath(key, { page }); diff --git a/src/routes/sub/dashboard.tsx b/src/routes/sub/dashboard.tsx index b7d1d39..c93b30e 100644 --- a/src/routes/sub/dashboard.tsx +++ b/src/routes/sub/dashboard.tsx @@ -50,6 +50,12 @@ export default function DashboardRoutes(): RouteObject[] { () => import("pages/dashboard/login-user/顧客ログインユーザ新規登録") ) ); + const 店舗ログインユーザ一覧 = Loadable( + lazy(() => import("pages/dashboard/login-user/店舗/一覧")) + ); + const 店舗ログインユーザ新規登録 = Loadable( + lazy(() => import("pages/dashboard/login-user/店舗/新規登録")) + ); const 店舗新規登録 = Loadable( lazy(() => import("pages/dashboard/shop/店舗新規登録")) ); @@ -108,14 +114,20 @@ export default function DashboardRoutes(): RouteObject[] { path: getPath(PageID.ログインユーザ_顧客新規登録), }, }, - // { - // pageId: PageID.ログインユーザ_店舗一覧, - // element: <顧客ログインユーザ一覧 />, - // }, - // { - // pageId: PageID.ログインユーザ_店舗新規登録, - // element: <顧客ログインユーザ新規登録 />, - // }, + { + pageId: PageID.ログインユーザ_店舗一覧, + ele: { + element: <店舗ログインユーザ一覧 />, + path: getPath(PageID.ログインユーザ_店舗一覧), + }, + }, + { + pageId: PageID.ログインユーザ_店舗新規登録, + ele: { + element: <店舗ログインユーザ新規登録 />, + path: getPath(PageID.ログインユーザ_店舗新規登録), + }, + }, { pageId: PageID.店舗新規登録, ele: { @@ -191,6 +203,13 @@ export default function DashboardRoutes(): RouteObject[] { ], }, }, + { + pageId: PageID.サービス券発行用QRコード, + ele: { + element: <サービス券発行用QRコード />, + path: getPath(PageID.サービス券発行用QRコード), + }, + }, ]; return allChildren