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++, LOGIN: id++,
LOGOUT: id++, LOGOUT: id++,

SEASON_TICKET_CONTRACTS: id++,
} as const; } as const;
export type ApiId = (typeof ApiId)[keyof typeof ApiId]; 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.ME]: "me",
[A.LOGIN]: "login", [A.LOGIN]: "login",
[A.LOGOUT]: "logout", [A.LOGOUT]: "logout",
[A.SEASON_TICKET_CONTRACTS]: "season-ticket-contracts",
}; };


const prefixs = { 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: "契約", label: "契約",
icon: <ArticleIcon />, icon: <ArticleIcon />,
id: PageID.DASHBOARD_CONTRACT_LIST,
id: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST,
}, },
{ {
label: "新規利用申込", label: "新規利用申込",
icon: <ArticleIcon />, icon: <ArticleIcon />,
id: PageID.DASHBOARD_CONTRACT_ENTRY,
id: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_ENTRY,
}, },
{ {
label: "領収証ダウンロード", label: "領収証ダウンロード",


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

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


export default function ContractDetail() { export default function ContractDetail() {
const { setHeaderTitle, setTabs } = useDashboard( const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_CONTRACT_DETAIL,
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL,
TabID.NONE 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(() => { useEffect(() => {
setHeaderTitle("契約詳細"); setHeaderTitle("契約詳細");
setTabs(null); setTabs(null);
}, [setHeaderTitle, setTabs]); }, [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 ( return (
<Box sx={{ p: 1, m: 1 }}>
<Box>
<Stack spacing={2}> <Stack spacing={2}>
<Box> <Box>
<Button
onClick={() => {
navigate(-1);
}}
>
戻る
</Button>
<Button onClick={moveToList}>戻る</Button>
</Box> </Box>
<Paper sx={{ p: 2 }}> <Paper sx={{ p: 2 }}>
<Typography variant="h5">契約情報</Typography> <Typography variant="h5">契約情報</Typography>
@@ -43,15 +72,18 @@ export default function ContractDetail() {
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableCell>駐車場名</TableCell> <TableCell>駐車場名</TableCell>
<TableCell>A駐車場</TableCell>
<TableCell>{seasonTicketContract.parking_name}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableCell>区画</TableCell> <TableCell>区画</TableCell>
<TableCell>1-1</TableCell>
<TableCell>{seasonTicketContract.room_no}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableCell>契約期間</TableCell> <TableCell>契約期間</TableCell>
<TableCell>2023/8/1-2024/7/31</TableCell>
<TableCell>
{seasonTicketContract.contract_start_date}-
{seasonTicketContract.contract_end_date}
</TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>


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

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


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


@@ -17,11 +17,8 @@ export default function ContractEntry() {
return ( return (
<Stack> <Stack>
<Box>新規の申込は、こちらよりお願いします。</Box> <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> </Link>
</Stack> </Stack>
); );


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

@@ -1,26 +1,44 @@
import { Box, Grid, Paper, Typography } from "@mui/material"; 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 useDashboard from "hooks/useDashBoard";
import useNavigateCustom from "hooks/useNavigateCustom"; import useNavigateCustom from "hooks/useNavigateCustom";
import { PageID, TabID } from "pages"; import { PageID, TabID } from "pages";
import { useEffect } from "react"; import { useEffect } from "react";
import { getPath } from "routes/path"; 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() { export default function ContractList() {
const { setHeaderTitle, setTabs } = useDashboard( const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_CONTRACT_LIST,
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST,
TabID.NONE TabID.NONE
); );


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


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


const moveToDetail = () => { const moveToDetail = () => {
navigateWhenChanged( navigateWhenChanged(
getPath(PageID.DASHBOARD_CONTRACT_DETAIL, {
getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL, {
query: { query: {
id: "test-test", id: "test-test",
}, },
@@ -35,13 +53,10 @@ export default function ContractList() {
return ( return (
<Box sx={{ p: 1, m: 1 }}> <Box sx={{ p: 1, m: 1 }}>
<Grid container spacing={2}> <Grid container spacing={2}>
{items.map((item, index) => {
{seasonTicketContracts.map((item, index) => {
return ( return (
<Grid item xs={12} md={6} key={index}> <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> </Grid>
); );
})} })}


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

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


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




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

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


DASHBOARD_OVERVIEW: id++, 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++, DASHBOARD_RECEIPT_DOWNLOAD: id++,




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

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


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

@@ -31,10 +31,11 @@ const getTabId = (key: PathKey): TabID => {
const PATHS_DASHBOARD = { const PATHS_DASHBOARD = {
[makePathKey(PageID.DASHBOARD_OVERVIEW)]: "/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", "/dashboard/contract/list/:page",
[makePathKey(PageID.DASHBOARD_CONTRACT_DETAIL)]:
[makePathKey(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL)]:
"/dashboard/contract/detail/:id", "/dashboard/contract/detail/:id",
[makePathKey(PageID.DASHBOARD_RECEIPT_DOWNLOAD)]: [makePathKey(PageID.DASHBOARD_RECEIPT_DOWNLOAD)]:
"/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 useAuth from "hooks/useAuth";
import DashboardLayout from "layouts/dashbord"; import DashboardLayout from "layouts/dashbord";
import { PageID } from "pages"; import { PageID } from "pages";
@@ -6,7 +7,7 @@ import { RouteObject } from "react-router-dom";
import { Loadable } from "routes"; import { Loadable } from "routes";
import { getRoute } from "routes/path"; import { getRoute } from "routes/path";


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


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