Browse Source

定期契約周り 全体的に整備

develop
sosuke.iwabuchi 2 years ago
parent
commit
6fe270c798
13 changed files with 242 additions and 62 deletions
  1. +2
    -0
      src/api/index.ts
  2. +26
    -0
      src/api/season-ticket-contract.ts
  3. +1
    -0
      src/api/url.ts
  4. +84
    -0
      src/contexts/dashboard/SeasonTicketContractContext.tsx
  5. +2
    -2
      src/layouts/dashbord/navigator.tsx
  6. +45
    -13
      src/pages/dashboard/contract/detail.tsx
  7. +3
    -6
      src/pages/dashboard/contract/entry.tsx
  8. +27
    -12
      src/pages/dashboard/contract/list.tsx
  9. +1
    -2
      src/pages/dashboard/user/detail.tsx
  10. +3
    -3
      src/pages/index.ts
  11. +1
    -1
      src/routes/index.tsx
  12. +4
    -3
      src/routes/path.ts
  13. +43
    -20
      src/routes/sub/dashboard.tsx

+ 2
- 0
src/api/index.ts View File

@@ -13,6 +13,8 @@ export const ApiId = {

LOGIN: id++,
LOGOUT: id++,

SEASON_TICKET_CONTRACTS: id++,
} as const;
export type ApiId = (typeof ApiId)[keyof typeof ApiId];



+ 26
- 0
src/api/season-ticket-contract.ts View File

@@ -0,0 +1,26 @@
import { APICommonResponse, ApiId, HttpMethod, request } from "api";
import { getUrl } from "./url";

export type SeasonTicketContract = {
season_ticekt_contract_record_no: string | null;
parking_name: string | null;
room_no: string | null;
season_ticket_seq_no: string | null;
vehicle_no: string | null;
vehicle_type: string | null;
contract_start_date: string | null;
contract_end_date: string | null;
revision: number;
};

type SeasonTicketContractsResponse = {
data: SeasonTicketContract[];
} & APICommonResponse;

export const getSeasonTicketContracts = async () => {
const res = await request<SeasonTicketContractsResponse>({
url: getUrl(ApiId.SEASON_TICKET_CONTRACTS),
method: HttpMethod.GET,
});
return res;
};

+ 1
- 0
src/api/url.ts View File

@@ -6,6 +6,7 @@ const urls = {
[A.ME]: "me",
[A.LOGIN]: "login",
[A.LOGOUT]: "logout",
[A.SEASON_TICKET_CONTRACTS]: "season-ticket-contracts",
};

const prefixs = {


+ 84
- 0
src/contexts/dashboard/SeasonTicketContractContext.tsx View File

@@ -0,0 +1,84 @@
import { HasChildren } from "@types";
import {
SeasonTicketContract,
getSeasonTicketContracts,
} from "api/season-ticket-contract";
import useAPICall from "hooks/useAPICall";
import useAuth from "hooks/useAuth";
import {
createContext,
useContext,
useEffect,
useLayoutEffect,
useState,
} from "react";

type ContextProps = {
initialized: boolean;
seasonTicketContracts: SeasonTicketContract[];
selectedseasonTicketContract: SeasonTicketContract | null;

fetch: VoidFunction;
select: (target: SeasonTicketContract | null) => void;
};
export const SeasonTicketContractContext = createContext<ContextProps>({
initialized: false,
seasonTicketContracts: [],
selectedseasonTicketContract: null,

fetch: () => {},
select: (target: SeasonTicketContract | null) => {},
});

type Props = HasChildren;
export function SeasonTicketContractContextProvider({ children }: Props) {
const { initialized, authenticated } = useAuth();
const [fetchInitialized, setFetchInitialized] = useState(false);

const [seasonTicketContracts, setSeasonTicketContracts] = useState<
SeasonTicketContract[]
>([]);
const [selectedseasonTicketContract, setSelectedseasonTicketContract] =
useState<SeasonTicketContract | null>(null);

const { callAPI: callGetSeasonTicketContracts } = useAPICall({
apiMethod: getSeasonTicketContracts,
backDrop: true,
onSuccess: ({ data }) => {
setSeasonTicketContracts(data);
setFetchInitialized(true);
},
onFailed: () => {
setSeasonTicketContracts([]);
setFetchInitialized(true);
},
});

const fetch = () => {
callGetSeasonTicketContracts({});
};

useEffect(() => {
if (authenticated) {
fetch();
}
}, [authenticated]);

return (
<SeasonTicketContractContext.Provider
value={{
initialized: fetchInitialized,
seasonTicketContracts,
selectedseasonTicketContract,
fetch,
select: setSelectedseasonTicketContract,
}}
>
{children}
</SeasonTicketContractContext.Provider>
);
}

export function useSeasonTicketContractContext() {
return useContext(SeasonTicketContractContext);
}

+ 2
- 2
src/layouts/dashbord/navigator.tsx View File

@@ -79,12 +79,12 @@ export default function Navigator(props: DrawerProps) {
{
label: "契約",
icon: <ArticleIcon />,
id: PageID.DASHBOARD_CONTRACT_LIST,
id: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST,
},
{
label: "新規利用申込",
icon: <ArticleIcon />,
id: PageID.DASHBOARD_CONTRACT_ENTRY,
id: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_ENTRY,
},
{
label: "領収証ダウンロード",


+ 45
- 13
src/pages/dashboard/contract/detail.tsx View File

@@ -9,33 +9,62 @@ import {
TableRow,
Typography,
} from "@mui/material";
import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext";
import useDashboard from "hooks/useDashBoard";
import useNavigateCustom from "hooks/useNavigateCustom";
import { PageID, TabID } from "pages";
import { useEffect } from "react";
import { useParams } from "react-router-dom";
import { getPath } from "routes/path";

export default function ContractDetail() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_CONTRACT_DETAIL,
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL,
TabID.NONE
);
const { navigate } = useNavigateCustom();

const { id: paramId } = useParams();

const {
initialized,
selectedseasonTicketContract: seasonTicketContract,
seasonTicketContracts,
select,
} = useSeasonTicketContractContext();

const { navigate, navigateWhenChanged } = useNavigateCustom();

const moveToList = () => {
navigateWhenChanged(getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST));
};

useEffect(() => {
setHeaderTitle("契約詳細");
setTabs(null);
}, [setHeaderTitle, setTabs]);

useEffect(() => {
if (initialized && !!paramId) {
const target = seasonTicketContracts.find((ele) => {
return ele.season_ticekt_contract_record_no === paramId;
});
if (target) {
select(target);
} else {
select(null);
moveToList();
}
}
}, [initialized]);

if (!initialized || seasonTicketContract === null) {
return null;
}
return (
<Box sx={{ p: 1, m: 1 }}>
<Box>
<Stack spacing={2}>
<Box>
<Button
onClick={() => {
navigate(-1);
}}
>
戻る
</Button>
<Button onClick={moveToList}>戻る</Button>
</Box>
<Paper sx={{ p: 2 }}>
<Typography variant="h5">契約情報</Typography>
@@ -43,15 +72,18 @@ export default function ContractDetail() {
<TableBody>
<TableRow>
<TableCell>駐車場名</TableCell>
<TableCell>A駐車場</TableCell>
<TableCell>{seasonTicketContract.parking_name}</TableCell>
</TableRow>
<TableRow>
<TableCell>区画</TableCell>
<TableCell>1-1</TableCell>
<TableCell>{seasonTicketContract.room_no}</TableCell>
</TableRow>
<TableRow>
<TableCell>契約期間</TableCell>
<TableCell>2023/8/1-2024/7/31</TableCell>
<TableCell>
{seasonTicketContract.contract_start_date}-
{seasonTicketContract.contract_end_date}
</TableCell>
</TableRow>
</TableBody>
</Table>


+ 3
- 6
src/pages/dashboard/contract/entry.tsx View File

@@ -5,7 +5,7 @@ import { useEffect } from "react";

export default function ContractEntry() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_CONTRACT_ENTRY,
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_ENTRY,
TabID.NONE
);

@@ -17,11 +17,8 @@ export default function ContractEntry() {
return (
<Stack>
<Box>新規の申込は、こちらよりお願いします。</Box>
<Link href="https://www.kyotopublic.or.jp/" target="_blank">
京都・滋賀駐車場なび
</Link>
<Link href="https://osaka-parking.jp/" target="_blank">
大阪・神戸・奈良駐車場なび
<Link href="https://www.kyotopublic.or.jp/teiki-parking/" target="_blank">
月極定期駐車場ナビ
</Link>
</Stack>
);


+ 27
- 12
src/pages/dashboard/contract/list.tsx View File

@@ -1,26 +1,44 @@
import { Box, Grid, Paper, Typography } from "@mui/material";
import { SeasonTicketContract } from "api/season-ticket-contract";
import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext";
import useDashboard from "hooks/useDashBoard";
import useNavigateCustom from "hooks/useNavigateCustom";
import { PageID, TabID } from "pages";
import { useEffect } from "react";
import { getPath } from "routes/path";

function SeasonTicketContractCard({ data }: { data: SeasonTicketContract }) {
const { navigateWhenChanged } = useNavigateCustom();
const handleClick = () => {
navigateWhenChanged(
getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL, {
query: {
id: data.season_ticekt_contract_record_no ?? "",
},
})
);
};
return (
<Paper sx={{ p: 2, cursor: "pointer" }} onClick={handleClick}>
<Typography variant="h5">{data.parking_name}</Typography>
<Typography variant="h6">区画:{data.room_no}</Typography>
</Paper>
);
}

export default function ContractList() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_CONTRACT_LIST,
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST,
TabID.NONE
);

const { navigateWhenChanged } = useNavigateCustom();
const { seasonTicketContracts } = useSeasonTicketContractContext();

const items = [
{ parkingName: "A駐車場", position: "1" },
{ parkingName: "B駐車場", position: "1-1" },
];
const { navigateWhenChanged } = useNavigateCustom();

const moveToDetail = () => {
navigateWhenChanged(
getPath(PageID.DASHBOARD_CONTRACT_DETAIL, {
getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL, {
query: {
id: "test-test",
},
@@ -35,13 +53,10 @@ export default function ContractList() {
return (
<Box sx={{ p: 1, m: 1 }}>
<Grid container spacing={2}>
{items.map((item, index) => {
{seasonTicketContracts.map((item, index) => {
return (
<Grid item xs={12} md={6} key={index}>
<Paper sx={{ p: 2, cursor: "pointer" }} onClick={moveToDetail}>
<Typography variant="h5">{item.parkingName}</Typography>
<Typography variant="h6">区画:{item.position}</Typography>
</Paper>
<SeasonTicketContractCard data={item} />
</Grid>
);
})}


+ 1
- 2
src/pages/dashboard/user/detail.tsx View File

@@ -1,12 +1,11 @@
import { Button, Stack } from "@mui/material";
import StackRow from "components/stack/StackRow";
import useDashboard from "hooks/useDashBoard";
import { PageID, TabID } from "pages";
import { useEffect } from "react";

export default function UserDetail() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_CONTRACT_DETAIL,
PageID.DASHBOARD_USER_DETAIL,
TabID.NONE
);



+ 3
- 3
src/pages/index.ts View File

@@ -7,9 +7,9 @@ export const PageID = {

DASHBOARD_OVERVIEW: id++,

DASHBOARD_CONTRACT_ENTRY: id++,
DASHBOARD_CONTRACT_LIST: id++,
DASHBOARD_CONTRACT_DETAIL: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_ENTRY: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_LIST: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL: id++,

DASHBOARD_RECEIPT_DOWNLOAD: id++,



+ 1
- 1
src/routes/index.tsx View File

@@ -41,7 +41,7 @@ export function Routes() {
return useRoutes([
CommonRoutes(),
AuthRoutes(),
DashboardRoutes(),
...DashboardRoutes(),
{
path: "403",
element: <Page403 />,


+ 4
- 3
src/routes/path.ts View File

@@ -31,10 +31,11 @@ const getTabId = (key: PathKey): TabID => {
const PATHS_DASHBOARD = {
[makePathKey(PageID.DASHBOARD_OVERVIEW)]: "/dashboard",
// --契約-----------------------
[makePathKey(PageID.DASHBOARD_CONTRACT_ENTRY)]: "/dashboard/contract/entry",
[makePathKey(PageID.DASHBOARD_CONTRACT_LIST)]:
[makePathKey(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_ENTRY)]:
"/dashboard/contract/entry",
[makePathKey(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST)]:
"/dashboard/contract/list/:page",
[makePathKey(PageID.DASHBOARD_CONTRACT_DETAIL)]:
[makePathKey(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL)]:
"/dashboard/contract/detail/:id",
[makePathKey(PageID.DASHBOARD_RECEIPT_DOWNLOAD)]:
"/dashboard/receipt/download",


+ 43
- 20
src/routes/sub/dashboard.tsx View File

@@ -1,3 +1,4 @@
import { SeasonTicketContractContextProvider } from "contexts/dashboard/SeasonTicketContractContext";
import useAuth from "hooks/useAuth";
import DashboardLayout from "layouts/dashbord";
import { PageID } from "pages";
@@ -6,7 +7,7 @@ import { RouteObject } from "react-router-dom";
import { Loadable } from "routes";
import { getRoute } from "routes/path";

export default function DashboardRoutes(): RouteObject {
export default function DashboardRoutes(): RouteObject[] {
const { authenticated } = useAuth();

const children: RouteObject[] = useMemo(() => {
@@ -16,12 +17,6 @@ export default function DashboardRoutes(): RouteObject {
const ContractEntry = Loadable(
lazy(() => import("pages/dashboard/contract/entry"))
);
const ContractList = Loadable(
lazy(() => import("pages/dashboard/contract/list"))
);
const ContractDetail = Loadable(
lazy(() => import("pages/dashboard/contract/detail"))
);
const ReceiptDownload = Loadable(
lazy(() => import("pages/dashboard/receipt/download"))
);
@@ -36,17 +31,9 @@ export default function DashboardRoutes(): RouteObject {
element: <Dashboard />,
},
{
pageId: PageID.DASHBOARD_CONTRACT_ENTRY,
pageId: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_ENTRY,
element: <ContractEntry />,
},
{
pageId: PageID.DASHBOARD_CONTRACT_LIST,
element: <ContractList />,
},
{
pageId: PageID.DASHBOARD_CONTRACT_DETAIL,
element: <ContractDetail />,
},
{
pageId: PageID.DASHBOARD_RECEIPT_DOWNLOAD,
element: <ReceiptDownload />,
@@ -66,8 +53,44 @@ export default function DashboardRoutes(): RouteObject {
}));
}, [authenticated]);

return {
element: <DashboardLayout />,
children: children,
};
const seasonTicketContractChildren: RouteObject[] = useMemo(() => {
if (!authenticated) return [];

const ContractList = Loadable(
lazy(() => import("pages/dashboard/contract/list"))
);
const ContractDetail = Loadable(
lazy(() => import("pages/dashboard/contract/detail"))
);

const allChildren = [
{
pageId: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST,
element: <ContractList />,
},
{
pageId: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL,
element: <ContractDetail />,
},
];
return allChildren.map(({ pageId, ...others }) => ({
...others,
path: getRoute(pageId),
}));
}, [authenticated]);

return [
{
element: <DashboardLayout />,
children: children,
},
{
element: (
<SeasonTicketContractContextProvider>
<DashboardLayout />
</SeasonTicketContractContextProvider>
),
children: seasonTicketContractChildren,
},
];
}

Loading…
Cancel
Save