浏览代码

契約関連の申請系を整備

develop
sosuke.iwabuchi 2 年前
父节点
当前提交
61b6ea97ab
共有 10 个文件被更改,包括 490 次插入7 次删除
  1. +5
    -0
      src/api/index.ts
  2. +68
    -3
      src/api/season-ticket-contract.ts
  3. +7
    -0
      src/api/url.ts
  4. +2
    -1
      src/components/hook-form/RHFCheckbox.tsx
  5. +25
    -3
      src/pages/dashboard/contract/detail.tsx
  6. +131
    -0
      src/pages/dashboard/contract/sticker-re-order.tsx
  7. +224
    -0
      src/pages/dashboard/contract/terminate-order.tsx
  8. +4
    -0
      src/pages/index.ts
  9. +10
    -0
      src/routes/path.ts
  10. +14
    -0
      src/routes/sub/dashboard.tsx

+ 5
- 0
src/api/index.ts 查看文件

@@ -16,6 +16,11 @@ export const ApiId = {

SEASON_TICKET_CONTRACTS: id++,
PAYMENT_PLANS: id++,

STICKER_RE_ORDER: id++,
PARKING_CERTIFICATE_ORDER: id++,
SEASON_TICKET_CONTRACT_TERMINATE_ORDER: id++,
UPDATE_VEHICLE_INFO_ORDER: id++,
} as const;
export type ApiId = (typeof ApiId)[keyof typeof ApiId];



+ 68
- 3
src/api/season-ticket-contract.ts 查看文件

@@ -26,7 +26,6 @@ export type PaymentPlan = {
type SeasonTicketContractsResponse = {
data: SeasonTicketContract[];
} & APICommonResponse;

export const getSeasonTicketContracts = async () => {
const res = await request<SeasonTicketContractsResponse>({
url: getUrl(ApiId.SEASON_TICKET_CONTRACTS),
@@ -39,11 +38,9 @@ export const getSeasonTicketContracts = async () => {
type PaymentPlansRequest = {
season_ticket_contract_record_no: string;
};

type PaymentPlansResponse = {
data: PaymentPlan[];
} & APICommonResponse;

export const getPaymentPlans = async (data: PaymentPlansRequest) => {
const res = await request<PaymentPlansResponse>({
url: getUrl(ApiId.PAYMENT_PLANS),
@@ -52,3 +49,71 @@ export const getPaymentPlans = async (data: PaymentPlansRequest) => {
});
return res;
};

// -------シール再発行依頼------------------
type StickerReOrderRequest = {
season_ticket_contract_record_no: string;
};
export const reOrderSticker = async (data: StickerReOrderRequest) => {
const res = await request({
url: getUrl(ApiId.STICKER_RE_ORDER),
method: HttpMethod.POST,
data: makeParam(data),
});
return res;
};

// -------車庫証明発行依頼------------------
type ParkingCertificateOrderRequest = {
season_ticket_contract_record_no: string;
date: Date;
reason: string;
reson_other: string;
opinion: string;
memo: string;
};
export const orderParkingCertificate = async (
data: ParkingCertificateOrderRequest
) => {
const res = await request({
url: getUrl(ApiId.PARKING_CERTIFICATE_ORDER),
method: HttpMethod.POST,
data: makeParam(data),
});
return res;
};

// -------解約依頼------------------
type TerminateOrderRequest = {
season_ticket_contract_record_no: string;
date: Date;
reason: string;
other_reason: string;
opinion: string;
memo: string;
};
export const orderSeasonTicketContractTerminate = async (
data: TerminateOrderRequest
) => {
const res = await request({
url: getUrl(ApiId.SEASON_TICKET_CONTRACT_TERMINATE_ORDER),
method: HttpMethod.POST,
data: makeParam(data),
});
return res;
};

// -------車両情報変更依頼------------------
type UpdateVehicleInfoOrderRequest = {
season_ticket_contract_record_no: string;
};
export const orderUpdateVehicleInfo = async (
data: UpdateVehicleInfoOrderRequest
) => {
const res = await request({
url: getUrl(ApiId.UPDATE_VEHICLE_INFO_ORDER),
method: HttpMethod.POST,
data: makeParam(data),
});
return res;
};

+ 7
- 0
src/api/url.ts 查看文件

@@ -8,6 +8,13 @@ const urls = {
[A.LOGOUT]: "logout",
[A.SEASON_TICKET_CONTRACTS]: "season-ticket-contracts",
[A.PAYMENT_PLANS]: "season-ticket-contract/payment-plans",
[A.STICKER_RE_ORDER]: "season-ticket-contract/sticker-re-order",
[A.PARKING_CERTIFICATE_ORDER]:
"season-ticket-contract/parking-certificate-order",
[A.SEASON_TICKET_CONTRACT_TERMINATE_ORDER]:
"season-ticket-contract/termination-order",
[A.UPDATE_VEHICLE_INFO_ORDER]:
"season-ticket-contract/update-vehicle-info-order",
};

const prefixs = {


+ 2
- 1
src/components/hook-form/RHFCheckbox.tsx 查看文件

@@ -6,6 +6,7 @@ import {
FormControlLabel,
FormGroup,
FormControlLabelProps,
Typography,
} from "@mui/material";
import { useMemo } from "react";

@@ -116,7 +117,7 @@ export function RHFMultiCheckbox({
onChange={() => field.onChange(onSelected(option.value))}
/>
}
label={option.label}
label={<Typography variant="body2">{option.label}</Typography>}
{...other}
/>
))}


+ 25
- 3
src/pages/dashboard/contract/detail.tsx 查看文件

@@ -130,15 +130,37 @@ export default function ContractDetail() {
</Paper>
<Paper sx={{ p: 2 }}>
<Typography variant="h5">各種申請</Typography>
<Stack direction="row" spacing={2} mt={2}>
<Stack spacing={2} mt={2}>
<Box>
<Button variant="contained">シール再発行申請</Button>
<Button
variant="contained"
onClick={() => {
navigateWhenChanged(
getPath(
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_STICKER_RE_ORDER
)
);
}}
>
シール再発行申請
</Button>
</Box>
<Box>
<Button variant="contained">駐車証明証申請</Button>
</Box>
<Box>
<Button variant="contained">解約申請</Button>
<Button
variant="contained"
onClick={() => {
navigateWhenChanged(
getPath(
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_TERMINATE_ORDER
)
);
}}
>
解約申請
</Button>
</Box>
<Box>
<Button variant="contained">車両情報変更申請</Button>


+ 131
- 0
src/pages/dashboard/contract/sticker-re-order.tsx 查看文件

@@ -0,0 +1,131 @@
import { Box, Button, Stack, Typography } from "@mui/material";
import { HasChildren } from "@types";
import { reOrderSticker } from "api/season-ticket-contract";
import { FormProvider, RHFTextField } from "components/hook-form";
import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext";
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, useState } from "react";
import { useForm } from "react-hook-form";
import { getPath } from "routes/path";

type AreaBoxProps = {
label: string;
} & HasChildren;
function AreaBox({ label, children }: AreaBoxProps) {
return (
<Box>
<Typography variant="body2">{label}</Typography>
{children}
</Box>
);
}

type FormProps = {};

export default function StickerReOrder() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_STICKER_RE_ORDER,
TabID.NONE
);

const form = useForm<FormProps>({});

const { navigateWhenChanged, navigate } = useNavigateCustom();

const { error } = useSnackbarCustom();

const { selectedseasonTicketContract } = useSeasonTicketContractContext();

const [done, setDone] = useState(false);

const { callAPI: callReOrderSticker } = useAPICall({
apiMethod: reOrderSticker,
backDrop: true,
onSuccess: () => {
setDone(true);
},
onFailed: () => {
error("依頼失敗しました");
},
});

const handleSubmit = () => {
if (selectedseasonTicketContract === null) return;
callReOrderSticker({
season_ticket_contract_record_no:
selectedseasonTicketContract.season_ticekt_contract_record_no ?? "",
});
};

useEffect(() => {
setHeaderTitle("シール再発行依頼");
setTabs(null);
}, [setHeaderTitle, setTabs]);

useEffect(() => {
if (selectedseasonTicketContract === null) {
navigateWhenChanged(
getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST)
);
}
}, [selectedseasonTicketContract]);

if (selectedseasonTicketContract === null) {
return null;
}
if (done) {
return (
<Box sx={{ mt: 1 }}>
<Stack spacing={2}>
<Box>依頼しました</Box>
<Box>
<Button
onClick={() => {
navigate(-1);
}}
>
戻る
</Button>
</Box>
</Stack>
</Box>
);
}

return (
<FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}>
<Box sx={{ mt: 1 }}>
<Stack spacing={2}>
<Box>
<Button
onClick={() => {
navigate(-1);
}}
>
戻る
</Button>
</Box>

<AreaBox label="申請理由">
<RHFTextField
name="reason"
size="small"
multiline
minRows={3}
maxRows={10}
/>
</AreaBox>
<Box>
<Button variant="contained" type="submit">
確定
</Button>
</Box>
</Stack>
</Box>
</FormProvider>
);
}

+ 224
- 0
src/pages/dashboard/contract/terminate-order.tsx 查看文件

@@ -0,0 +1,224 @@
import { Box, Button, Stack, Typography } from "@mui/material";
import { HasChildren } from "@types";
import {
orderSeasonTicketContractTerminate,
reOrderSticker,
} from "api/season-ticket-contract";
import RequireChip from "components/chip/RequireChip";
import {
FormProvider,
RHFCheckbox,
RHFMultiCheckbox,
RHFSelect,
RHFTextField,
} from "components/hook-form";
import RHFDatePicker from "components/hook-form/RHFDatePicker";
import { SelectOptionProps } from "components/hook-form/RHFSelect";
import StackRow from "components/stack/StackRow";
import { useSeasonTicketContractContext } from "contexts/dashboard/SeasonTicketContractContext";
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";

type AreaBoxProps = {
label: string;
require?: boolean;
} & HasChildren;
function AreaBox({ label, children, require }: AreaBoxProps) {
return (
<Box>
<StackRow>
<Typography variant="subtitle1">〇{label}</Typography>
<RequireChip require={require ?? false} />
</StackRow>
{children}
</Box>
);
}

type FormProps = {
date: Date | null;
reason: string[];
other_reason: string;
opinion: string;
memo: string;
};

export default function TerminateOrder() {
const { setHeaderTitle, setTabs } = useDashboard(
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_TERMINATE_ORDER,
TabID.NONE
);

const form = useForm<FormProps>({
defaultValues: {
date: null,
reason: [],
other_reason: "",
opinion: "",
memo: "",
},
});

const { navigateWhenChanged, navigate } = useNavigateCustom();

const { error } = useSnackbarCustom();

const { selectedseasonTicketContract } = useSeasonTicketContractContext();

const [done, setDone] = useState(false);

const { callAPI: callOrderSeasonTicketContractTerminate } = useAPICall({
apiMethod: orderSeasonTicketContractTerminate,
backDrop: true,
onSuccess: () => {
setDone(true);
},
onFailed: () => {
error("依頼失敗しました");
},
});

const handleSubmit = (data: FormProps) => {
console.log(data);

if (selectedseasonTicketContract === null) return;
const date = data.date;
if (date === null) return;

callOrderSeasonTicketContractTerminate({
...data,
date,
season_ticket_contract_record_no:
selectedseasonTicketContract.season_ticekt_contract_record_no ?? "",
reason: data.reason.join(","),
});
};

const reasons = useMemo(() => {
return [
"転居/転勤のため",
"就職/進学/卒業のため",
"料金が高いため",
"支払いが困難なため",
"車/バイク/自転車に乗らなくなったため",
"より良い駐車場/駐輪場が見つかったため",
"駐車場/駐輪場に不満があるため(詳細)",
"その他(詳細)",
].map((ele, index) => ({
label: String(index + 1) + "." + String(ele),
value: ele,
}));
}, []);

useEffect(() => {
setHeaderTitle("解約依頼申請");
setTabs(null);
}, [setHeaderTitle, setTabs]);

useEffect(() => {
if (selectedseasonTicketContract === null) {
navigateWhenChanged(
getPath(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_LIST)
);
}
}, [selectedseasonTicketContract]);

if (selectedseasonTicketContract === null) {
return null;
}
if (done) {
return (
<Box sx={{ mt: 1 }}>
<Stack spacing={2}>
<Box>依頼しました</Box>
<Box>
<Button
onClick={() => {
navigate(-1);
}}
>
戻る
</Button>
</Box>
</Stack>
</Box>
);
}

return (
<FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}>
<Box sx={{ mt: 1 }}>
<Stack spacing={2}>
<Box>
<Button
onClick={() => {
navigate(-1);
}}
>
戻る
</Button>
</Box>

<AreaBox label="解約希望日" require>
<RHFDatePicker name="date" size="small" />
</AreaBox>
<AreaBox label="解約理由(複数選択可)" require>
<Typography variant="body2">
解約の理由についてお聞かせ下さい(複数選択可)
</Typography>

<RHFMultiCheckbox name="reason" options={reasons} />
</AreaBox>
<AreaBox label="解約理由詳細">
<Typography variant="body2">
前質問 7・8を選択された方 詳細を詳しくお聞かせください。
</Typography>
<RHFTextField
name="reason_other"
size="small"
multiline
minRows={3}
maxRows={10}
/>
</AreaBox>
<AreaBox label="ご意見">
<Typography variant="body2">
今後の管理運営に生かすため、ご意見がありましたらご記入ください。
</Typography>
<RHFTextField
name="opinion"
size="small"
multiline
minRows={3}
maxRows={10}
/>
</AreaBox>
<AreaBox label="備考">
<Typography variant="body2">
ご不明点等がございましたらご入力ください。お電話またはメールにて回答させていただきます。
</Typography>
<RHFTextField
name="memo"
size="small"
multiline
minRows={3}
maxRows={10}
/>
</AreaBox>

<Box>
<Button variant="contained" type="submit">
確定
</Button>
</Box>
</Stack>
</Box>
</FormProvider>
);
}

+ 4
- 0
src/pages/index.ts 查看文件

@@ -10,6 +10,10 @@ export const PageID = {
DASHBOARD_SEASON_TICKET_CONTRACT_ENTRY: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_LIST: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_STICKER_RE_ORDER: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_PARKING_CERTIFICATE_ORDER: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_TERMINATE_ORDER: id++,
DASHBOARD_SEASON_TICKET_CONTRACT_UPDATE_VEHICLE_INFO_ORDER: id++,

DASHBOARD_RECEIPT_DOWNLOAD: id++,



+ 10
- 0
src/routes/path.ts 查看文件

@@ -37,6 +37,16 @@ const PATHS_DASHBOARD = {
"/dashboard/contract/list/:page",
[makePathKey(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL)]:
"/dashboard/contract/detail/:id",
[makePathKey(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_STICKER_RE_ORDER)]:
"/dashboard/contract/sticker-re-order",
[makePathKey(
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_PARKING_CERTIFICATE_ORDER
)]: "/dashboard/contract/parking-certificate-order",
[makePathKey(PageID.DASHBOARD_SEASON_TICKET_CONTRACT_TERMINATE_ORDER)]:
"/dashboard/contract/terminate-order",
[makePathKey(
PageID.DASHBOARD_SEASON_TICKET_CONTRACT_UPDATE_VEHICLE_INFO_ORDER
)]: "/dashboard/contract/update-vehicle-info-order",
[makePathKey(PageID.DASHBOARD_RECEIPT_DOWNLOAD)]:
"/dashboard/receipt/download",
[makePathKey(PageID.DASHBOARD_USER_DETAIL)]: "/dashboard/user/detail",


+ 14
- 0
src/routes/sub/dashboard.tsx 查看文件

@@ -62,6 +62,12 @@ export default function DashboardRoutes(): RouteObject[] {
const ContractDetail = Loadable(
lazy(() => import("pages/dashboard/contract/detail"))
);
const StickerReOrder = Loadable(
lazy(() => import("pages/dashboard/contract/sticker-re-order"))
);
const TerminateOrder = Loadable(
lazy(() => import("pages/dashboard/contract/terminate-order"))
);

const allChildren = [
{
@@ -72,6 +78,14 @@ export default function DashboardRoutes(): RouteObject[] {
pageId: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_DETAIL,
element: <ContractDetail />,
},
{
pageId: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_STICKER_RE_ORDER,
element: <StickerReOrder />,
},
{
pageId: PageID.DASHBOARD_SEASON_TICKET_CONTRACT_TERMINATE_ORDER,
element: <TerminateOrder />,
},
];
return allChildren.map(({ pageId, ...others }) => ({
...others,


正在加载...
取消
保存