Просмотр исходного кода

領収証発行依頼一覧全般

develop
sosuke.iwabuchi 2 лет назад
Родитель
Сommit
0751593dee
14 измененных файлов: 275 добавлений и 73 удалений
  1. +15
    -0
      src/api/app.ts
  2. +37
    -0
      src/api/custom/hello-techno/receipt-issuing-order.ts
  3. +4
    -0
      src/api/index.ts
  4. +12
    -0
      src/api/url.ts
  5. +2
    -0
      src/codes/page.ts
  6. +18
    -0
      src/codes/receipt-issuing-order.ts
  7. +48
    -0
      src/contexts/AppContext.tsx
  8. +3
    -3
      src/contexts/SearchConditionContext.tsx
  9. +8
    -0
      src/hooks/useApp.ts
  10. +48
    -0
      src/pages/app/ReceiptIssuingOrder.tsx
  11. +52
    -67
      src/pages/dashboard/receipt-issuing-order/list.tsx
  12. +23
    -2
      src/routes/index.tsx
  13. +4
    -0
      src/routes/path.ts
  14. +1
    -1
      src/theme/index.tsx

+ 15
- 0
src/api/app.ts Просмотреть файл

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

export type CheckTokenRequest = {
access_token: string;
};

export const checkToken = async (data: CheckTokenRequest) => {
const res = await request({
url: getUrl(ApiId.APP_TOKEN_CHECK),
method: HttpMethod.GET,
data: new URLSearchParams(data),
});
return res;
};

+ 37
- 0
src/api/custom/hello-techno/receipt-issuing-order.ts Просмотреть файл

@@ -6,6 +6,7 @@ import {
request,
} from "api";
import { getUrl } from "api/url";
import { ReceiptIssuingOrderStatus } from "codes/receipt-issuing-order";

export type HTCustomer = {
customer_code: string;
@@ -50,3 +51,39 @@ export const createReceiptIssuingOrder = async (
});
return res;
};

export type ReceiptIssuingOrder = {
id: string;
order_datetime: string;
customer_code: string;
parking_management_code: string;
customer_name: string;
parking_name: string;
status: ReceiptIssuingOrderStatus;
handler_id: string;
handler_name: string;
};

export type ReceiptIssuingOrdersRequest = {
customer_code?: string;
customer_name?: string;
parking_management_code?: string;
parking_name?: string;
};

export type ReceiptIssuingOrdersResponse = {
data: {
records: ReceiptIssuingOrder[];
};
} & APICommonResponse;

export const getReceiptIssuingOrders = async (
data: ReceiptIssuingOrdersRequest
) => {
const res = await request<ReceiptIssuingOrdersResponse>({
url: getUrl(ApiId.HT_CUSTOM_RECEIPT_ISSUING_ORDERS),
method: HttpMethod.GET,
data: new URLSearchParams(data),
});
return res;
};

+ 4
- 0
src/api/index.ts Просмотреть файл

@@ -13,6 +13,9 @@ export const ApiId = {
LOGIN: id++,
LOGOUT: id++,

APP_TOKEN_CHECK: id++,
DOWNLOAD_RECEIPT: id++,

RECEIPT_ISSUING_ORDERS: id++,
RECEIPT_ISSUING_ORDER: id++,
RECEIPT_ISSUING_ORDER_CREATE: id++,
@@ -21,6 +24,7 @@ export const ApiId = {
HT_CUSTOM_CUSTOMERS: id++,
HT_CUSTOM_PARKINGS: id++,
HT_CUSTOM_ADJUST_DATA: id++,
HT_CUSTOM_RECEIPT_ISSUING_ORDERS: id++,
HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE: id++,
} as const;
export type ApiId = (typeof ApiId)[keyof typeof ApiId];


+ 12
- 0
src/api/url.ts Просмотреть файл

@@ -1,4 +1,6 @@
import { env } from "process";
import { ApiId as A } from ".";
import { HOST_API } from "config";

const urls = {
[A.CSRF_TOKEN]: "sanctum/csrf-cookie",
@@ -6,18 +8,24 @@ const urls = {
[A.LOGIN]: "login",
[A.LOGOUT]: "logout",

[A.APP_TOKEN_CHECK]: "app-token-check",
[A.DOWNLOAD_RECEIPT]: "receipt/download",

[A.RECEIPT_ISSUING_ORDERS]: "receipt-issuing-orders",

// FOR CUSTOM
[A.HT_CUSTOM_CUSTOMERS]: "custom/hello-techno/customers",
[A.HT_CUSTOM_PARKINGS]: "custom/hello-techno/parkings",
[A.HT_CUSTOM_ADJUST_DATA]: "custom/hello-techno/adjust-data",
[A.HT_CUSTOM_RECEIPT_ISSUING_ORDERS]:
"custom/hello-techno/receipt-issuing-orders",
[A.HT_CUSTOM_RECEIPT_ISSUING_ORDER_CREATE]:
"custom/hello-techno/receipt-issuing-order/create",
};

const prefixs = {
[A.CSRF_TOKEN]: "",
[A.DOWNLOAD_RECEIPT]: "",
};
const DEFAULT_API_URL_PREFIX = "api";

@@ -32,3 +40,7 @@ export const getUrl = (apiId: A) => {
}
return url + (urls[apiId] ?? "");
};

export const getFullUrl = (apiId: A) => {
return HOST_API + "/" + getUrl(apiId);
};

+ 2
- 0
src/codes/page.ts Просмотреть файл

@@ -5,6 +5,8 @@ export const PageID = {
LOGIN: id++,
LOGOUT: id++,

APP_RECEIPT_ISSUING_ORDER_INDEX: id++,

DASHBOARD_OVERVIEW: id++,

DASHBOARD_CONTRACT_LIST: id++,


+ 18
- 0
src/codes/receipt-issuing-order.ts Просмотреть файл

@@ -20,3 +20,21 @@ export const ReceiptIssuingOrderStatus = {

export type ReceiptIssuingOrderStatus =
(typeof ReceiptIssuingOrderStatus)[keyof typeof ReceiptIssuingOrderStatus];

const ReceiptIssuingOrderStatusName = {
[ReceiptIssuingOrderStatus.NONE]: "",
[ReceiptIssuingOrderStatus.CREATED]: "受付済み",
[ReceiptIssuingOrderStatus.SMS_SENDING]: "SMS送信中",
[ReceiptIssuingOrderStatus.SMS_RECEIVED]: "SMS送信完了",
[ReceiptIssuingOrderStatus.SMS_OPENED]: "SMS開封済み",
[ReceiptIssuingOrderStatus.MAIL_REQUEST]: "郵送依頼中",
[ReceiptIssuingOrderStatus.PREPARING_FOR_MAIL]: "郵送準備中",
[ReceiptIssuingOrderStatus.MAIL_DONE]: "郵送投函済み",
[ReceiptIssuingOrderStatus.EMAIL_SENDING]: "メール送信中",
[ReceiptIssuingOrderStatus.EMAIL_DONE]: "メール送信済み",
[ReceiptIssuingOrderStatus.DOWNLOAD_DONE]: "ダウンロード済み",
} as const;

export function getStatusName(status: ReceiptIssuingOrderStatus): string {
return ReceiptIssuingOrderStatusName[status];
}

+ 48
- 0
src/contexts/AppContext.tsx Просмотреть файл

@@ -0,0 +1,48 @@
import { HasChildren } from "@types";
import { checkToken } from "api/app";
import useAPICall from "hooks/useAPICall";
import { createContext, useState } from "react";

type App = {
token: string;
tokenResult: "cheking" | "ok" | "ng";
setToken: (token: string) => void;
};

export const AppContext = createContext<App>({
token: "",
tokenResult: "cheking",
setToken: (token: string) => {},
});

type Props = HasChildren;
export function AppContextProvider({ children }: Props) {
const [token, _setToken] = useState("");

const [tokenResult, setTokenResult] = useState<"cheking" | "ok" | "ng">(
"cheking"
);

const checkTokenAPI = useAPICall({
apiMethod: checkToken,
onSuccess: (res, sendData) => {
setTokenResult("ok");
_setToken(sendData.access_token);
},
onFailed: () => {
setTokenResult("ng");
},
});

const setToken = (token: string) => {
checkTokenAPI.callAPI({
access_token: token,
});
};

return (
<AppContext.Provider value={{ token, tokenResult, setToken }}>
{children}
</AppContext.Provider>
);
}

+ 3
- 3
src/contexts/SearchConditionContext.tsx Просмотреть файл

@@ -14,7 +14,9 @@ const initialState = {
condition: _condition,
get: (key: string): string => "",
initializeCondition: () => {},
addCondition: (condition: Dictionary) => {},
addCondition: (condition: Dictionary) => {
console.log("not init SearchConditionContext");
},
clearCondition: () => {},
};

@@ -45,7 +47,6 @@ export function SearchConditionContextProvider({ children }: Props) {
}

if (!isEqual(after, condition)) {
console.log("initialCondition", { before: condition, after });
setCondition(after, "initializeCondition");
}
setInitialized(true);
@@ -72,7 +73,6 @@ export function SearchConditionContextProvider({ children }: Props) {
});

if (!isEqual(before, after)) {
console.log("addCondition", { additional, before, after });
setCondition(after, "addCondition");
}
};


+ 8
- 0
src/hooks/useApp.ts Просмотреть файл

@@ -0,0 +1,8 @@
import { AppContext } from "contexts/AppContext";
import { useContext } from "react";

export default function useApp() {
const context = useContext(AppContext);

return context;
}

+ 48
- 0
src/pages/app/ReceiptIssuingOrder.tsx Просмотреть файл

@@ -0,0 +1,48 @@
import { Box, Button, Paper, Stack, Typography } from "@mui/material";
import { ApiId } from "api";
import { getFullUrl } from "api/url";
import useApp from "hooks/useApp";
import { useEffect, useMemo } from "react";
import { useParams } from "react-router-dom";

export default function ReceiptIssuingOrder() {
const { token: paramToken } = useParams();

const { token, setToken, tokenResult } = useApp();

const downloadUrl = useMemo(() => {
return getFullUrl(ApiId.DOWNLOAD_RECEIPT) + "?access_token=" + token;
}, [token]);

useEffect(() => {
if (paramToken) {
setToken(paramToken);
console.log("render");
}
}, []);

if (tokenResult === "cheking") {
return null;
}

if (tokenResult === "ng") {
return <Box>不正なアクセス</Box>;
}

return (
<Box sx={{ p: 3, pt: 5, mx: "auto", maxWidth: 500 }} textAlign="center">
<Stack spacing={3}>
<Typography variant="h5">領収証発行依頼</Typography>

<Paper>
<Typography variant="h5">状況</Typography>
</Paper>
<Paper>
<Button href={downloadUrl} variant="contained">
PDFダウンロード
</Button>
</Paper>
</Stack>
</Box>
);
}

+ 52
- 67
src/pages/dashboard/receipt-issuing-order/list.tsx Просмотреть файл

@@ -7,26 +7,24 @@ import {
TableContainer,
TablePagination,
TableRow,
TextField,
} from "@mui/material";
import { Dictionary } from "@types";
import {
ReceiptIssuingOrder,
getReceiptIssuingOrders,
} from "api/receipt-issuing-order";
} from "api/custom/hello-techno/receipt-issuing-order";
import { PageID, TabID } from "codes/page";
import { ReceiptIssuingOrderStatus } from "codes/receipt-issuing-order";
import { getStatusName } from "codes/receipt-issuing-order";
import { FormProvider, RHFTextField } from "components/hook-form";
import { TableHeadCustom } from "components/table";
import { SearchConditionContextProvider } from "contexts/SearchConditionContext";
import useAPICall from "hooks/useAPICall";
import useBackDrop from "hooks/useBackDrop";
import useDashboard from "hooks/useDashBoard";
import useSearchConditionContext from "hooks/useSearchConditionContext";
import useTable, { UseTableReturn } from "hooks/useTable";
import ContractTabs from "layouts/dashbord/tab/ContractTabs";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { Contract } from "types/contract";

export default function ReceiptIssuingOrderList() {
const { setHeaderTitle, setTabs } = useDashboard(
@@ -34,8 +32,6 @@ export default function ReceiptIssuingOrderList() {
TabID.NONE
);

const table = useTable<ReceiptIssuingOrder>();

useEffect(() => {
setHeaderTitle("領収証発行依頼一覧");
setTabs(null);
@@ -43,33 +39,14 @@ export default function ReceiptIssuingOrderList() {

return (
<SearchConditionContextProvider>
<Page table={table} />
<Page />
</SearchConditionContextProvider>
);
}

type CommonProps = {
table: UseTableReturn<ReceiptIssuingOrder>;
};
function Page({ table }: CommonProps) {
const {
order,
page,
sort,
rowsPerPage,
fetched,
fillteredRow,
isNotFound,
dataLength,
//
onSort,
onChangePage,
onChangeRowsPerPage,
//
setRowData,
//
ROWS_PER_PAGES,
} = table;
function Page() {
const table = useTable<ReceiptIssuingOrder>();

return (
<Box>
<SearchBox table={table} />
@@ -79,7 +56,11 @@ function Page({ table }: CommonProps) {
}

type FormProps = {
address: string;
customer_name: string;
parking_name: string;
};
type CommonProps = {
table: UseTableReturn<ReceiptIssuingOrder>;
};
function SearchBox({ table }: CommonProps) {
const {
@@ -89,13 +70,20 @@ function SearchBox({ table }: CommonProps) {
addCondition: add,
} = useSearchConditionContext();

const { setShowBackDrop } = useBackDrop();

const form = useForm<FormProps>({
defaultValues: {
address: "",
customer_name: "",
parking_name: "",
},
});

const { callAPI: calGetReceiptIssuingOrders, makeSendData } = useAPICall({
const {
callAPI: calGetReceiptIssuingOrders,
makeSendData,
sending,
} = useAPICall({
apiMethod: getReceiptIssuingOrders,
form,
onSuccess: (res) => {
@@ -111,6 +99,10 @@ function SearchBox({ table }: CommonProps) {
add({ ...data });
};

const handleBlur = () => {
addCondition(form.getValues());
};

const fetch = async (data: Dictionary) => {
const sendData = makeSendData({
...data,
@@ -121,7 +113,8 @@ function SearchBox({ table }: CommonProps) {
// 初期値設定
useEffect(() => {
if (initialized) {
form.setValue("address", get("address"));
form.setValue("customer_name", get("customer_name"));
form.setValue("parking_name", get("parking_name"));
}
}, [initialized, condition]);

@@ -132,38 +125,32 @@ function SearchBox({ table }: CommonProps) {
}
}, [condition, initialized]);

// バックドロップ
useEffect(() => {
setShowBackDrop(sending);
}, [sending]);

return (
<FormProvider methods={form} onSubmit={form.handleSubmit(handleSubmit)}>
<Box sx={{ p: 1, m: 1 }}>
<Grid container spacing={1}>
<Grid item xs={3}>
<RHFTextField
label="ステータス"
name="status"
label="運営会社名"
name="customer_name"
fullWidth
size="small"
onBlur={handleBlur}
/>
</Grid>
<Grid item xs={3}>
<TextField label="a" fullWidth size="small" />
</Grid>
<Grid item xs={3}>
<TextField label="a" fullWidth size="small" />
</Grid>
<Grid item xs={3}>
<TextField label="a" fullWidth size="small" />
</Grid>
<Grid item xs={3}>
<TextField label="a" fullWidth size="small" />
</Grid>
<Grid item xs={3}>
<TextField label="a" fullWidth size="small" />
</Grid>
<Grid item xs={3}>
<TextField label="a" fullWidth size="small" />
</Grid>
<Grid item xs={3}>
<TextField label="a" fullWidth size="small" />
<RHFTextField
label="駐車場名"
name="parking_name"
fullWidth
size="small"
onBlur={handleBlur}
/>
</Grid>
</Grid>
</Box>
@@ -173,9 +160,11 @@ function SearchBox({ table }: CommonProps) {

function TableBox({ table }: CommonProps) {
const TABLE_HEAD = [
{ id: "id", label: "ID", align: "left" },
{ id: "name", label: "名前", align: "left" },
{ id: "emply", label: "---", align: "left" },
{ id: "order_datetime", label: "受付時刻", align: "left" },
{ id: "customer_name", label: "運営会社名", align: "left" },
{ id: "parking_name", label: "駐車場名", align: "left" },
{ id: "status", label: "ステータス", align: "left" },
{ id: "handler_name", label: "担当者", align: "left" },
];
const {
order,
@@ -196,13 +185,6 @@ function TableBox({ table }: CommonProps) {
ROWS_PER_PAGES,
} = table;

useEffect(() => {
setRowData([
{ id: "iwabuchi", status: ReceiptIssuingOrderStatus.NONE },
{ id: "iwabuchi", status: ReceiptIssuingOrderStatus.MAIL_DONE },
]);
}, []);

return (
<>
<TableContainer
@@ -250,8 +232,11 @@ type RowProps = {
function Row({ data }: RowProps) {
return (
<TableRow hover sx={{ cursor: "pointer" }}>
<TableCell>{data.id}</TableCell>
<TableCell>{data.status}</TableCell>
<TableCell>{data.order_datetime}</TableCell>
<TableCell>{data.customer_name}</TableCell>
<TableCell>{data.parking_name}</TableCell>
<TableCell>{getStatusName(data.status)}</TableCell>
<TableCell>{data.handler_name}</TableCell>
</TableRow>
);
}

+ 23
- 2
src/routes/index.tsx Просмотреть файл

@@ -1,12 +1,13 @@
import { PageID } from "codes/page";
import { UserRole } from "codes/user";
import LoadingScreen from "components/LoadingScreen";
import { AppContextProvider } from "contexts/AppContext";
import useAuth from "hooks/useAuth";
import DashboardLayout from "layouts/dashbord";
import SimpleLayout from "layouts/simple";
import { ElementType, Suspense, lazy, useMemo } from "react";
import { RouteObject, useRoutes } from "react-router-dom";
import { getRoute } from "./path";
import useAuth from "hooks/useAuth";
import { UserRole } from "codes/user";

const Loadable = (Component: ElementType) => (props: any) => {
return (
@@ -30,6 +31,20 @@ const AuthRoutes = (): RouteObject => ({
],
});

const AppRoutes = (): RouteObject => ({
element: (
<AppContextProvider>
<SimpleLayout />
</AppContextProvider>
),
children: [
{
path: getRoute(PageID.APP_RECEIPT_ISSUING_ORDER_INDEX),
element: <ReceiptIssuingOrder />,
},
],
});

const DashboardRoutes = (): RouteObject => {
const { canAccess } = useAuth();

@@ -80,6 +95,7 @@ export function Routes() {
const { initialized } = useAuth();
return useRoutes([
AuthRoutes(),
AppRoutes(),
DashboardRoutes(),
{
path: "403",
@@ -96,6 +112,11 @@ export function Routes() {
const Login = Loadable(lazy(() => import("pages/auth/login")));
const Logout = Loadable(lazy(() => import("pages/auth/logout")));

// App ---------------------------
const ReceiptIssuingOrder = Loadable(
lazy(() => import("pages/app/ReceiptIssuingOrder"))
);

//ダッシュボード ----------------------------
const Dashboard = Loadable(lazy(() => import("pages/dashboard")));
// 契約関連


+ 4
- 0
src/routes/path.ts Просмотреть файл

@@ -37,6 +37,10 @@ const PATHS = {

[makePathKey(PageID.DASHBOARD_OVERVIEW)]: "/dashboard",

// APP
[makePathKey(PageID.APP_RECEIPT_ISSUING_ORDER_INDEX)]:
"/app/receipt-issuing-oreder/:token",

// 契約関連
[makePathKey(PageID.DASHBOARD_CONTRACT_LIST)]:
"/dashboard/contract/list/:page",


+ 1
- 1
src/theme/index.tsx Просмотреть файл

@@ -153,7 +153,7 @@ theme = {
styleOverrides: {
root: {
"&.Mui-disabled:before": {
"border-bottom-style": "none",
borderBottomStyle: "none",
},
},
},


Загрузка…
Отмена
Сохранить