bananas-commerce-admin 0.21.2 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/Admin.js +35 -9
- package/dist/esm/Admin.js.map +1 -1
- package/dist/esm/extensions/pim/components/ProductRow.js +16 -0
- package/dist/esm/extensions/pim/components/ProductRow.js.map +1 -1
- package/dist/esm/extensions/pim/pages/product/list.js +1 -0
- package/dist/esm/extensions/pim/pages/product/list.js.map +1 -1
- package/dist/esm/extensions/user/components/InviteUserModal.js +106 -0
- package/dist/esm/extensions/user/components/InviteUserModal.js.map +1 -0
- package/dist/esm/extensions/user/index.js +30 -0
- package/dist/esm/extensions/user/index.js.map +1 -0
- package/dist/esm/extensions/user/pages/staff/detail.js +143 -0
- package/dist/esm/extensions/user/pages/staff/detail.js.map +1 -0
- package/dist/esm/extensions/user/pages/staff/list.js +61 -0
- package/dist/esm/extensions/user/pages/staff/list.js.map +1 -0
- package/dist/esm/extensions/user/types/staff.js +2 -0
- package/dist/esm/extensions/user/types/staff.js.map +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pages/AcceptInvitePage.js +125 -0
- package/dist/esm/pages/AcceptInvitePage.js.map +1 -0
- package/dist/esm/pages/ResetPasswordPage.js +125 -0
- package/dist/esm/pages/ResetPasswordPage.js.map +1 -0
- package/dist/types/extensions/pim/types/product.d.ts +1 -0
- package/dist/types/extensions/user/components/InviteUserModal.d.ts +9 -0
- package/dist/types/extensions/user/index.d.ts +4 -0
- package/dist/types/extensions/user/pages/staff/detail.d.ts +4 -0
- package/dist/types/extensions/user/pages/staff/list.d.ts +4 -0
- package/dist/types/extensions/user/types/staff.d.ts +24 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/pages/AcceptInvitePage.d.ts +9 -0
- package/dist/types/pages/ResetPasswordPage.d.ts +9 -0
- package/package.json +1 -1
- package/src/Admin.tsx +53 -26
- package/src/extensions/pim/components/ProductRow.tsx +32 -0
- package/src/extensions/pim/pages/product/list.tsx +1 -0
- package/src/extensions/pim/types/product.ts +1 -0
- package/src/extensions/user/components/InviteUserModal.tsx +179 -0
- package/src/extensions/user/index.tsx +51 -0
- package/src/extensions/user/pages/staff/detail.tsx +262 -0
- package/src/extensions/user/pages/staff/list.tsx +100 -0
- package/src/extensions/user/types/staff.ts +27 -0
- package/src/index.ts +1 -0
- package/src/pages/AcceptInvitePage.tsx +232 -0
- package/src/pages/ResetPasswordPage.tsx +236 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { useSearchParams } from "react-router-dom";
|
|
3
|
+
import LoadingButton from "@mui/lab/LoadingButton";
|
|
4
|
+
import { Alert, Backdrop, Box, Dialog, DialogActions, DialogContent, DialogTitle, Stack, TextField, Typography, } from "@mui/material";
|
|
5
|
+
import { styled } from "@mui/material/styles";
|
|
6
|
+
import { useSnackbar } from "notistack";
|
|
7
|
+
import Brand from "../components/Brand";
|
|
8
|
+
import Content from "../containers/Content";
|
|
9
|
+
import { useApi } from "../contexts/ApiContext";
|
|
10
|
+
import { useI18n } from "../contexts/I18nContext";
|
|
11
|
+
const StyledDialog = styled(Dialog, {
|
|
12
|
+
name: "BananasAcceptInviteDialog",
|
|
13
|
+
slot: "Root",
|
|
14
|
+
})(() => ({}));
|
|
15
|
+
const StyledDialogTitle = styled(DialogTitle, {
|
|
16
|
+
name: "BananasAcceptInviteDialog",
|
|
17
|
+
slot: "Title",
|
|
18
|
+
})(({ theme }) => theme.unstable_sx({
|
|
19
|
+
bgcolor: "primary.main",
|
|
20
|
+
color: "primary.contrastText",
|
|
21
|
+
}));
|
|
22
|
+
const StyledBackdrop = styled(Backdrop, {
|
|
23
|
+
name: "BananasAcceptInviteDialog",
|
|
24
|
+
slot: "Backdrop",
|
|
25
|
+
})(({ theme }) => theme.unstable_sx({
|
|
26
|
+
bgcolor: "primary.dark",
|
|
27
|
+
m: 0,
|
|
28
|
+
p: 2,
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
alignItems: "middle",
|
|
31
|
+
justifyContent: "center",
|
|
32
|
+
display: "flex",
|
|
33
|
+
}));
|
|
34
|
+
export const AcceptInvitePage = ({ title, logo, logoHeight }) => {
|
|
35
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
36
|
+
const { t } = useI18n();
|
|
37
|
+
const api = useApi();
|
|
38
|
+
const [searchParams] = useSearchParams();
|
|
39
|
+
const [password, setPassword] = useState("");
|
|
40
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
41
|
+
const [loading, setLoading] = useState(false);
|
|
42
|
+
const [error, setError] = useState("");
|
|
43
|
+
const [tokenError, setTokenError] = useState("");
|
|
44
|
+
const token = searchParams.get("token");
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!token) {
|
|
47
|
+
setTokenError(t("No invite token provided"));
|
|
48
|
+
}
|
|
49
|
+
}, [token, t]);
|
|
50
|
+
const handleSubmit = async (event) => {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
setError("");
|
|
53
|
+
if (!token) {
|
|
54
|
+
setTokenError(t("No invite token provided"));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (password.length < 8) {
|
|
58
|
+
setError(t("Password must be at least 8 characters long"));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (password !== confirmPassword) {
|
|
62
|
+
setError(t("Passwords do not match"));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
setLoading(true);
|
|
66
|
+
try {
|
|
67
|
+
const response = await api?.operations["user.staff:invite-accept"].call({
|
|
68
|
+
body: {
|
|
69
|
+
token,
|
|
70
|
+
password,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
if (response?.ok) {
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
enqueueSnackbar(data.message || t("User created successfully!"), {
|
|
76
|
+
variant: "success",
|
|
77
|
+
});
|
|
78
|
+
// User is already logged in on the backend, redirect to dashboard
|
|
79
|
+
// Use full page navigation to reinitialize the UserContext
|
|
80
|
+
window.location.href = "/";
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const errorData = await response?.json();
|
|
84
|
+
if (errorData?.detail && Array.isArray(errorData.detail)) {
|
|
85
|
+
const tokenErrors = errorData.detail.filter((err) => err.loc?.includes("token"));
|
|
86
|
+
if (tokenErrors.length > 0) {
|
|
87
|
+
setTokenError(tokenErrors[0].msg);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
setError(errorData.detail[0]?.msg || t("Failed to accept invite"));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
setError(t("Failed to accept invite. Please try again."));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error("[ACCEPT_INVITE]", error);
|
|
100
|
+
setError(t("An unexpected error occurred. Please try again."));
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
setLoading(false);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
return (React.createElement(Content, { layout: "fullWidth" },
|
|
107
|
+
React.createElement(StyledDialog, { open: true, BackdropComponent: StyledBackdrop, PaperProps: { elevation: 1 }, sx: { "> * > *": { width: "100%" } } },
|
|
108
|
+
React.createElement(StyledDialogTitle, null, logo ? (React.createElement(Brand, { LogoProps: { style: { width: "auto", height: logoHeight ?? "24px !important" } }, src: logo })) : (React.createElement(Typography, { sx: { fontWeight: "bold", color: "inherit" } }, title))),
|
|
109
|
+
React.createElement(Box, { component: "form", onSubmit: handleSubmit },
|
|
110
|
+
React.createElement(DialogContent, null,
|
|
111
|
+
React.createElement(Stack, { spacing: 2 },
|
|
112
|
+
React.createElement(Typography, { variant: "h6" }, t("Accept Staff Invite")),
|
|
113
|
+
React.createElement(Typography, { color: "text.secondary", variant: "body2" }, t("Set your password to complete your account setup.")),
|
|
114
|
+
tokenError && React.createElement(Alert, { severity: "error" }, tokenError),
|
|
115
|
+
error && !tokenError && React.createElement(Alert, { severity: "error" }, error),
|
|
116
|
+
!tokenError && (React.createElement(React.Fragment, null,
|
|
117
|
+
React.createElement(TextField, { fullWidth: true, required: true, color: "secondary", disabled: loading, inputProps: { "aria-label": "Password", minLength: 8 }, label: t("Password"), name: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value) }),
|
|
118
|
+
React.createElement(TextField, { fullWidth: true, required: true, color: "secondary", disabled: loading, inputProps: { "aria-label": "Confirm Password", minLength: 8 }, label: t("Confirm Password"), name: "confirmPassword", type: "password", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value) }))))),
|
|
119
|
+
React.createElement(DialogActions, { sx: {
|
|
120
|
+
pt: 0,
|
|
121
|
+
pb: 2,
|
|
122
|
+
} }, !tokenError && (React.createElement(LoadingButton, { "aria-label": "accept-invite", color: "primary", disabled: !token, loading: loading, sx: { margin: "auto" }, type: "submit", variant: "contained" }, t("Create Account"))))))));
|
|
123
|
+
};
|
|
124
|
+
export default AcceptInvitePage;
|
|
125
|
+
//# sourceMappingURL=AcceptInvitePage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AcceptInvitePage.js","sourceRoot":"","sources":["../../../src/pages/AcceptInvitePage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import { useSearchParams } from "react-router-dom";
|
|
3
|
+
import LoadingButton from "@mui/lab/LoadingButton";
|
|
4
|
+
import { Alert, Backdrop, Box, Dialog, DialogActions, DialogContent, DialogTitle, Stack, TextField, Typography, } from "@mui/material";
|
|
5
|
+
import { styled } from "@mui/material/styles";
|
|
6
|
+
import { useSnackbar } from "notistack";
|
|
7
|
+
import Brand from "../components/Brand";
|
|
8
|
+
import Content from "../containers/Content";
|
|
9
|
+
import { useApi } from "../contexts/ApiContext";
|
|
10
|
+
import { useI18n } from "../contexts/I18nContext";
|
|
11
|
+
const StyledDialog = styled(Dialog, {
|
|
12
|
+
name: "BananasResetPasswordDialog",
|
|
13
|
+
slot: "Root",
|
|
14
|
+
})(() => ({}));
|
|
15
|
+
const StyledDialogTitle = styled(DialogTitle, {
|
|
16
|
+
name: "BananasResetPasswordDialog",
|
|
17
|
+
slot: "Title",
|
|
18
|
+
})(({ theme }) => theme.unstable_sx({
|
|
19
|
+
bgcolor: "primary.main",
|
|
20
|
+
color: "primary.contrastText",
|
|
21
|
+
}));
|
|
22
|
+
const StyledBackdrop = styled(Backdrop, {
|
|
23
|
+
name: "BananasResetPasswordDialog",
|
|
24
|
+
slot: "Backdrop",
|
|
25
|
+
})(({ theme }) => theme.unstable_sx({
|
|
26
|
+
bgcolor: "primary.dark",
|
|
27
|
+
m: 0,
|
|
28
|
+
p: 2,
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
alignItems: "middle",
|
|
31
|
+
justifyContent: "center",
|
|
32
|
+
display: "flex",
|
|
33
|
+
}));
|
|
34
|
+
export const ResetPasswordPage = ({ title, logo, logoHeight, }) => {
|
|
35
|
+
const { enqueueSnackbar } = useSnackbar();
|
|
36
|
+
const { t } = useI18n();
|
|
37
|
+
const api = useApi();
|
|
38
|
+
const [searchParams] = useSearchParams();
|
|
39
|
+
const [password, setPassword] = useState("");
|
|
40
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
41
|
+
const [loading, setLoading] = useState(false);
|
|
42
|
+
const [error, setError] = useState("");
|
|
43
|
+
const [tokenError, setTokenError] = useState("");
|
|
44
|
+
const token = searchParams.get("token");
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (!token) {
|
|
47
|
+
setTokenError(t("No password reset token provided"));
|
|
48
|
+
}
|
|
49
|
+
}, [token, t]);
|
|
50
|
+
const handleSubmit = async (event) => {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
setError("");
|
|
53
|
+
if (!token) {
|
|
54
|
+
setTokenError(t("No password reset token provided"));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (password.length < 8) {
|
|
58
|
+
setError(t("Password must be at least 8 characters long"));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (password !== confirmPassword) {
|
|
62
|
+
setError(t("Passwords do not match"));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
setLoading(true);
|
|
66
|
+
try {
|
|
67
|
+
const response = await api?.operations["user.staff:password-reset-confirm"].call({
|
|
68
|
+
body: {
|
|
69
|
+
token,
|
|
70
|
+
new_password: password,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
if (response?.ok) {
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
enqueueSnackbar(data.message || t("Password reset successfully!"), {
|
|
76
|
+
variant: "success",
|
|
77
|
+
});
|
|
78
|
+
// User is logged in on the backend after password reset, redirect to dashboard
|
|
79
|
+
// Use full page navigation to reinitialize the UserContext
|
|
80
|
+
window.location.href = "/";
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const errorData = await response?.json();
|
|
84
|
+
if (errorData?.detail && Array.isArray(errorData.detail)) {
|
|
85
|
+
const tokenErrors = errorData.detail.filter((err) => err.loc?.includes("token"));
|
|
86
|
+
if (tokenErrors.length > 0) {
|
|
87
|
+
setTokenError(tokenErrors[0].msg);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
setError(errorData.detail[0]?.msg || t("Failed to reset password"));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
setError(t("Failed to reset password. Please try again."));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error("[RESET_PASSWORD]", error);
|
|
100
|
+
setError(t("An unexpected error occurred. Please try again."));
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
setLoading(false);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
return (React.createElement(Content, { layout: "fullWidth" },
|
|
107
|
+
React.createElement(StyledDialog, { open: true, BackdropComponent: StyledBackdrop, PaperProps: { elevation: 1 }, sx: { "> * > *": { width: "100%" } } },
|
|
108
|
+
React.createElement(StyledDialogTitle, null, logo ? (React.createElement(Brand, { LogoProps: { style: { width: "auto", height: logoHeight ?? "24px !important" } }, src: logo })) : (React.createElement(Typography, { sx: { fontWeight: "bold", color: "inherit" } }, title))),
|
|
109
|
+
React.createElement(Box, { component: "form", onSubmit: handleSubmit },
|
|
110
|
+
React.createElement(DialogContent, null,
|
|
111
|
+
React.createElement(Stack, { spacing: 2 },
|
|
112
|
+
React.createElement(Typography, { variant: "h6" }, t("Reset Your Password")),
|
|
113
|
+
React.createElement(Typography, { color: "text.secondary", variant: "body2" }, t("Enter your new password below.")),
|
|
114
|
+
tokenError && React.createElement(Alert, { severity: "error" }, tokenError),
|
|
115
|
+
error && !tokenError && React.createElement(Alert, { severity: "error" }, error),
|
|
116
|
+
!tokenError && (React.createElement(React.Fragment, null,
|
|
117
|
+
React.createElement(TextField, { fullWidth: true, required: true, color: "secondary", disabled: loading, inputProps: { "aria-label": "New Password", minLength: 8 }, label: t("New Password"), name: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value) }),
|
|
118
|
+
React.createElement(TextField, { fullWidth: true, required: true, color: "secondary", disabled: loading, inputProps: { "aria-label": "Confirm New Password", minLength: 8 }, label: t("Confirm New Password"), name: "confirmPassword", type: "password", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value) }))))),
|
|
119
|
+
React.createElement(DialogActions, { sx: {
|
|
120
|
+
pt: 0,
|
|
121
|
+
pb: 2,
|
|
122
|
+
} }, !tokenError && (React.createElement(LoadingButton, { "aria-label": "reset-password", color: "primary", disabled: !token, loading: loading, sx: { margin: "auto" }, type: "submit", variant: "contained" }, t("Reset Password"))))))));
|
|
123
|
+
};
|
|
124
|
+
export default ResetPasswordPage;
|
|
125
|
+
//# sourceMappingURL=ResetPasswordPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResetPasswordPage.js","sourceRoot":"","sources":["../../../src/pages/ResetPasswordPage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ export interface ProductList {
|
|
|
5
5
|
name: string;
|
|
6
6
|
description: string;
|
|
7
7
|
is_active: boolean;
|
|
8
|
+
image_url: string | null;
|
|
8
9
|
}
|
|
9
10
|
export type ProductPropertyValue = string | number | boolean | string[] | number[] | boolean[] | null | undefined;
|
|
10
11
|
export type ProductPropertiesData = Record<string, string | number | boolean | string[] | number[] | boolean[]>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { PageProps } from "../../../types";
|
|
3
|
+
export interface InviteUserModalProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
setOpen: (open: boolean) => void;
|
|
6
|
+
refresh: PageProps["refresh"];
|
|
7
|
+
}
|
|
8
|
+
export declare const InviteUserModal: React.FC<InviteUserModalProps>;
|
|
9
|
+
export default InviteUserModal;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface StaffList {
|
|
2
|
+
id: number;
|
|
3
|
+
email: string;
|
|
4
|
+
is_active: boolean;
|
|
5
|
+
groups: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface StaffDetail {
|
|
8
|
+
id: number;
|
|
9
|
+
email: string;
|
|
10
|
+
is_staff: boolean;
|
|
11
|
+
is_active: boolean;
|
|
12
|
+
is_superuser: boolean;
|
|
13
|
+
groups: string[];
|
|
14
|
+
permissions: string[];
|
|
15
|
+
last_login: string | null;
|
|
16
|
+
date_created: string;
|
|
17
|
+
}
|
|
18
|
+
export interface GroupOption {
|
|
19
|
+
id: number;
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
22
|
+
export interface StaffOptions {
|
|
23
|
+
groups: GroupOption[];
|
|
24
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -70,6 +70,7 @@ export * as pos from "./extensions/pos";
|
|
|
70
70
|
export * as pricing from "./extensions/pricing";
|
|
71
71
|
export * as report from "./extensions/report";
|
|
72
72
|
export * as subscription from "./extensions/subscription";
|
|
73
|
+
export * as user from "./extensions/user";
|
|
73
74
|
export * as mui from "./mui";
|
|
74
75
|
export type { RouterExtension } from "./router/Router";
|
|
75
76
|
export * as themes from "./themes";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { LogoType } from "../types";
|
|
3
|
+
export interface AcceptInvitePageProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
logo?: LogoType;
|
|
6
|
+
logoHeight?: number | string;
|
|
7
|
+
}
|
|
8
|
+
export declare const AcceptInvitePage: React.FC<AcceptInvitePageProps>;
|
|
9
|
+
export default AcceptInvitePage;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { LogoType } from "../types";
|
|
3
|
+
export interface ResetPasswordPageProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
logo?: LogoType;
|
|
6
|
+
logoHeight?: number | string;
|
|
7
|
+
}
|
|
8
|
+
export declare const ResetPasswordPage: React.FC<ResetPasswordPageProps>;
|
|
9
|
+
export default ResetPasswordPage;
|
package/package.json
CHANGED
package/src/Admin.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { BrowserRouter } from "react-router-dom";
|
|
2
|
+
import { BrowserRouter, useLocation } from "react-router-dom";
|
|
3
3
|
|
|
4
4
|
import { Stack } from "@mui/material";
|
|
5
5
|
|
|
@@ -10,7 +10,9 @@ import DialogContextProvider, { BcomDialog } from "./contexts/DialogContext";
|
|
|
10
10
|
import { useI18n } from "./contexts/I18nContext";
|
|
11
11
|
import { RouterContextProvider } from "./contexts/RouterContext";
|
|
12
12
|
import { useUser } from "./contexts/UserContext";
|
|
13
|
+
import AcceptInvitePage from "./pages/AcceptInvitePage";
|
|
13
14
|
import LoginPage from "./pages/LoginPage";
|
|
15
|
+
import ResetPasswordPage from "./pages/ResetPasswordPage";
|
|
14
16
|
import { Router, RouterProps } from "./router/Router";
|
|
15
17
|
import { LogoType, NavigationOverrides } from "./types";
|
|
16
18
|
|
|
@@ -31,7 +33,7 @@ export interface AdminProps extends RouterProps {
|
|
|
31
33
|
basepath?: string;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
const AdminContent: React.FC<AdminProps> = ({
|
|
35
37
|
logo,
|
|
36
38
|
logoSymbol,
|
|
37
39
|
loginLogoHeight,
|
|
@@ -47,10 +49,56 @@ export const Admin: React.FC<AdminProps> = ({
|
|
|
47
49
|
const api = useApi();
|
|
48
50
|
const i18n = useI18n();
|
|
49
51
|
const { hasTriedToFetchUser, user } = useUser();
|
|
52
|
+
const location = useLocation();
|
|
50
53
|
|
|
51
54
|
const hasLoaded = Boolean(api != null && i18n != null);
|
|
52
55
|
const hasUser = user != null;
|
|
53
56
|
|
|
57
|
+
// Check if we're on public routes
|
|
58
|
+
const isAcceptInviteRoute = location.pathname === "/user/accept-invite";
|
|
59
|
+
const isResetPasswordRoute = location.pathname === "/user/reset-password";
|
|
60
|
+
|
|
61
|
+
if (!hasLoaded || !hasTriedToFetchUser) {
|
|
62
|
+
return <LoadingScreen />;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Show accept invite page if on that route, regardless of auth status
|
|
66
|
+
if (isAcceptInviteRoute) {
|
|
67
|
+
return <AcceptInvitePage logo={logo} logoHeight={loginLogoHeight} title={title} />;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Show reset password page if on that route, regardless of auth status
|
|
71
|
+
if (isResetPasswordRoute) {
|
|
72
|
+
return <ResetPasswordPage logo={logo} logoHeight={loginLogoHeight} title={title} />;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Show login page if not authenticated
|
|
76
|
+
if (!hasUser) {
|
|
77
|
+
return <LoginPage logo={logo} logoHeight={loginLogoHeight} title={title} />;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Show authenticated content
|
|
81
|
+
return (
|
|
82
|
+
<RouterContextProvider basename={basename} stripPathPrefix={basepath}>
|
|
83
|
+
<DialogContextProvider>
|
|
84
|
+
<BcomDialog />
|
|
85
|
+
<Stack direction={{ xs: "column", sm: "row" }}>
|
|
86
|
+
<NavRail
|
|
87
|
+
logo={logoSymbol ?? logo}
|
|
88
|
+
navigation={navigation}
|
|
89
|
+
subtitle={subtitle}
|
|
90
|
+
title={title}
|
|
91
|
+
version={version}
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
<Router dashboard={dashboard} extensions={extensions} />
|
|
95
|
+
</Stack>
|
|
96
|
+
</DialogContextProvider>
|
|
97
|
+
</RouterContextProvider>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const Admin: React.FC<AdminProps> = (props) => {
|
|
54
102
|
return (
|
|
55
103
|
<Stack
|
|
56
104
|
sx={{
|
|
@@ -59,30 +107,9 @@ export const Admin: React.FC<AdminProps> = ({
|
|
|
59
107
|
bgcolor: "background.default",
|
|
60
108
|
}}
|
|
61
109
|
>
|
|
62
|
-
{
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
<LoginPage logo={logo} logoHeight={loginLogoHeight} title={title} />
|
|
66
|
-
) : (
|
|
67
|
-
<BrowserRouter basename={basename}>
|
|
68
|
-
<RouterContextProvider basename={basename} stripPathPrefix={basepath}>
|
|
69
|
-
<DialogContextProvider>
|
|
70
|
-
<BcomDialog />
|
|
71
|
-
<Stack direction={{ xs: "column", sm: "row" }}>
|
|
72
|
-
<NavRail
|
|
73
|
-
logo={logoSymbol ?? logo}
|
|
74
|
-
navigation={navigation}
|
|
75
|
-
subtitle={subtitle}
|
|
76
|
-
title={title}
|
|
77
|
-
version={version}
|
|
78
|
-
/>
|
|
79
|
-
|
|
80
|
-
<Router dashboard={dashboard} extensions={extensions} />
|
|
81
|
-
</Stack>
|
|
82
|
-
</DialogContextProvider>
|
|
83
|
-
</RouterContextProvider>
|
|
84
|
-
</BrowserRouter>
|
|
85
|
-
)}
|
|
110
|
+
<BrowserRouter basename={props.basename}>
|
|
111
|
+
<AdminContent {...props} />
|
|
112
|
+
</BrowserRouter>
|
|
86
113
|
</Stack>
|
|
87
114
|
);
|
|
88
115
|
};
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
|
|
3
3
|
import CancelIcon from "@mui/icons-material/Cancel";
|
|
4
4
|
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
|
5
|
+
import { Box } from "@mui/material";
|
|
5
6
|
|
|
6
7
|
import { TableCell } from "../../../components/Table/TableCell";
|
|
7
8
|
import { NavigatingTableRow } from "../../../components/Table/TableRow";
|
|
@@ -13,6 +14,37 @@ export interface ProductRowProps {
|
|
|
13
14
|
|
|
14
15
|
export const ProductRow: React.FC<ProductRowProps> = ({ product }) => (
|
|
15
16
|
<NavigatingTableRow route="pim.product:detail" routeParams={{ id: product.id }}>
|
|
17
|
+
<TableCell
|
|
18
|
+
sx={{ py: 0.75 }}
|
|
19
|
+
typographyProps={{
|
|
20
|
+
component: "div",
|
|
21
|
+
sx: { display: "flex", alignItems: "center", width: 48 },
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
{product.image_url ? (
|
|
25
|
+
<Box
|
|
26
|
+
alt=""
|
|
27
|
+
component="img"
|
|
28
|
+
src={product.image_url}
|
|
29
|
+
sx={{
|
|
30
|
+
width: 48,
|
|
31
|
+
height: 48,
|
|
32
|
+
borderRadius: 1,
|
|
33
|
+
bgcolor: "background.default",
|
|
34
|
+
objectFit: "cover",
|
|
35
|
+
}}
|
|
36
|
+
/>
|
|
37
|
+
) : (
|
|
38
|
+
<Box
|
|
39
|
+
sx={{
|
|
40
|
+
width: 48,
|
|
41
|
+
height: 48,
|
|
42
|
+
borderRadius: 1,
|
|
43
|
+
bgcolor: "action.hover",
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
)}
|
|
47
|
+
</TableCell>
|
|
16
48
|
<TableCell>{product.name}</TableCell>
|
|
17
49
|
<TableCell>{product.item_type}</TableCell>
|
|
18
50
|
<TableCell>{product.number}</TableCell>
|
|
@@ -55,6 +55,7 @@ const ProductListPage: PageComponent<LimitOffset<ProductList>> = ({ data }) => {
|
|
|
55
55
|
<TableCard>
|
|
56
56
|
<Table pagination count={data?.count}>
|
|
57
57
|
<TableHead>
|
|
58
|
+
<TableHeading sx={{ width: 80 }}>{t("Image")}</TableHeading>
|
|
58
59
|
<TableHeading>{t("Name")}</TableHeading>
|
|
59
60
|
<TableHeading>{t("Type")}</TableHeading>
|
|
60
61
|
<TableHeading>{t("Product Number")}</TableHeading>
|