bananas-commerce-admin 0.21.2 → 0.22.1
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/ProductPropertiesCard.js +12 -0
- package/dist/esm/extensions/pim/components/ProductPropertiesCard.js.map +1 -1
- package/dist/esm/extensions/pim/components/ProductPropertyField.js +3 -3
- package/dist/esm/extensions/pim/components/ProductPropertyField.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 +2 -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/ProductPropertiesCard.tsx +12 -0
- package/src/extensions/pim/components/ProductPropertyField.tsx +3 -2
- 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 +2 -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
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"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: "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":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,aAAa,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,KAAK,EACL,QAAQ,EACR,GAAG,EACH,MAAM,EACN,aAAa,EACb,aAAa,EACb,WAAW,EACX,KAAK,EACL,SAAS,EACT,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,MAAM,qBAAqB,CAAC;AACxC,OAAO,OAAO,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AASlD,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE;IAClC,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE,MAAM;CACb,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEf,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,EAAE;IAC5C,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE,OAAO;CACd,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACf,KAAK,CAAC,WAAW,CAAC;IAChB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,sBAAsB;CAC9B,CAAC,CACH,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,EAAE;IACtC,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE,UAAU;CACjB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACf,KAAK,CAAC,WAAW,CAAC;IAChB,OAAO,EAAE,cAAc;IACvB,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,cAAc,EAAE,QAAQ;IACxB,OAAO,EAAE,MAAM;CAChB,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAoC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;IAC/F,MAAM,EAAE,eAAe,EAAE,GAAG,WAAW,EAAE,CAAC;IAC1C,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,YAAY,CAAC,GAAG,eAAe,EAAE,CAAC;IAEzC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEjD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,aAAa,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAEf,MAAM,YAAY,GAAG,KAAK,EAAE,KAAsB,EAAE,EAAE;QACpD,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEb,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,aAAa,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,CAAC,CAAC,6CAA6C,CAAC,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;YACjC,QAAQ,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,CAAC;QAEjB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,EAAE,UAAU,CAAC,0BAA0B,CAAC,CAAC,IAAI,CAAC;gBACtE,IAAI,EAAE;oBACJ,KAAK;oBACL,QAAQ;iBACT;aACF,CAAC,CAAC;YAEH,IAAI,QAAQ,EAAE,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,eAAe,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,4BAA4B,CAAC,EAAE;oBAC/D,OAAO,EAAE,SAAS;iBACnB,CAAC,CAAC;gBAEH,kEAAkE;gBAClE,2DAA2D;gBAC3D,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,MAAM,SAAS,GAAG,MAAM,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACzC,IAAI,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzD,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAqC,EAAE,EAAE,CACpF,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAC3B,CAAC;oBACF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC3B,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;oBACpC,CAAC;yBAAM,CAAC;wBACN,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC;oBACrE,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,CAAC,CAAC,4CAA4C,CAAC,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;YACxC,QAAQ,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAC,CAAC;QACjE,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,oBAAC,OAAO,IAAC,MAAM,EAAC,WAAW;QACzB,oBAAC,YAAY,IACX,IAAI,QACJ,iBAAiB,EAAE,cAAc,EACjC,UAAU,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,EAC5B,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAEpC,oBAAC,iBAAiB,QACf,IAAI,CAAC,CAAC,CAAC,CACN,oBAAC,KAAK,IACJ,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,IAAI,iBAAiB,EAAE,EAAE,EAChF,GAAG,EAAE,IAAI,GACT,CACH,CAAC,CAAC,CAAC,CACF,oBAAC,UAAU,IAAC,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAG,KAAK,CAAc,CAC/E,CACiB;YAEpB,oBAAC,GAAG,IAAC,SAAS,EAAC,MAAM,EAAC,QAAQ,EAAE,YAAY;gBAC1C,oBAAC,aAAa;oBACZ,oBAAC,KAAK,IAAC,OAAO,EAAE,CAAC;wBACf,oBAAC,UAAU,IAAC,OAAO,EAAC,IAAI,IAAE,CAAC,CAAC,qBAAqB,CAAC,CAAc;wBAChE,oBAAC,UAAU,IAAC,KAAK,EAAC,gBAAgB,EAAC,OAAO,EAAC,OAAO,IAC/C,CAAC,CAAC,mDAAmD,CAAC,CAC5C;wBAEZ,UAAU,IAAI,oBAAC,KAAK,IAAC,QAAQ,EAAC,OAAO,IAAE,UAAU,CAAS;wBAE1D,KAAK,IAAI,CAAC,UAAU,IAAI,oBAAC,KAAK,IAAC,QAAQ,EAAC,OAAO,IAAE,KAAK,CAAS;wBAE/D,CAAC,UAAU,IAAI,CACd;4BACE,oBAAC,SAAS,IACR,SAAS,QACT,QAAQ,QACR,KAAK,EAAC,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,EAAE,EACtD,KAAK,EAAE,CAAC,CAAC,UAAU,CAAC,EACpB,IAAI,EAAC,UAAU,EACf,IAAI,EAAC,UAAU,EACf,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAC5C;4BACF,oBAAC,SAAS,IACR,SAAS,QACT,QAAQ,QACR,KAAK,EAAC,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,EAAE,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC,EAAE,EAC9D,KAAK,EAAE,CAAC,CAAC,kBAAkB,CAAC,EAC5B,IAAI,EAAC,iBAAiB,EACtB,IAAI,EAAC,UAAU,EACf,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GACnD,CACD,CACJ,CACK,CACM;gBAEhB,oBAAC,aAAa,IACZ,EAAE,EAAE;wBACF,EAAE,EAAE,CAAC;wBACL,EAAE,EAAE,CAAC;qBACN,IAEA,CAAC,UAAU,IAAI,CACd,oBAAC,aAAa,kBACD,eAAe,EAC1B,KAAK,EAAC,SAAS,EACf,QAAQ,EAAE,CAAC,KAAK,EAChB,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EACtB,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,WAAW,IAElB,CAAC,CAAC,gBAAgB,CAAC,CACN,CACjB,CACa,CACZ,CACO,CACP,CACX,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -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":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,aAAa,MAAM,wBAAwB,CAAC;AACnD,OAAO,EACL,KAAK,EACL,QAAQ,EACR,GAAG,EACH,MAAM,EACN,aAAa,EACb,aAAa,EACb,WAAW,EACX,KAAK,EACL,SAAS,EACT,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,MAAM,qBAAqB,CAAC;AACxC,OAAO,OAAO,MAAM,uBAAuB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AASlD,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE;IAClC,IAAI,EAAE,4BAA4B;IAClC,IAAI,EAAE,MAAM;CACb,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEf,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,EAAE;IAC5C,IAAI,EAAE,4BAA4B;IAClC,IAAI,EAAE,OAAO;CACd,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACf,KAAK,CAAC,WAAW,CAAC;IAChB,OAAO,EAAE,cAAc;IACvB,KAAK,EAAE,sBAAsB;CAC9B,CAAC,CACH,CAAC;AAEF,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,EAAE;IACtC,IAAI,EAAE,4BAA4B;IAClC,IAAI,EAAE,UAAU;CACjB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACf,KAAK,CAAC,WAAW,CAAC;IAChB,OAAO,EAAE,cAAc;IACvB,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,SAAS,EAAE,QAAQ;IACnB,UAAU,EAAE,QAAQ;IACpB,cAAc,EAAE,QAAQ;IACxB,OAAO,EAAE,MAAM;CAChB,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAqC,CAAC,EAClE,KAAK,EACL,IAAI,EACJ,UAAU,GACX,EAAE,EAAE;IACH,MAAM,EAAE,eAAe,EAAE,GAAG,WAAW,EAAE,CAAC;IAC1C,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,YAAY,CAAC,GAAG,eAAe,EAAE,CAAC;IAEzC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEjD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,aAAa,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAEf,MAAM,YAAY,GAAG,KAAK,EAAE,KAAsB,EAAE,EAAE;QACpD,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEb,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,aAAa,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,CAAC,CAAC,6CAA6C,CAAC,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;YACjC,QAAQ,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,CAAC;QAEjB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,EAAE,UAAU,CAAC,mCAAmC,CAAC,CAAC,IAAI,CAAC;gBAC/E,IAAI,EAAE;oBACJ,KAAK;oBACL,YAAY,EAAE,QAAQ;iBACvB;aACF,CAAC,CAAC;YAEH,IAAI,QAAQ,EAAE,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,eAAe,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,8BAA8B,CAAC,EAAE;oBACjE,OAAO,EAAE,SAAS;iBACnB,CAAC,CAAC;gBAEH,+EAA+E;gBAC/E,2DAA2D;gBAC3D,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,MAAM,SAAS,GAAG,MAAM,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACzC,IAAI,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;oBACzD,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAqC,EAAE,EAAE,CACpF,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAC3B,CAAC;oBACF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC3B,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;oBACpC,CAAC;yBAAM,CAAC;wBACN,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC;oBACtE,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,CAAC,CAAC,6CAA6C,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;YACzC,QAAQ,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAC,CAAC;QACjE,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,oBAAC,OAAO,IAAC,MAAM,EAAC,WAAW;QACzB,oBAAC,YAAY,IACX,IAAI,QACJ,iBAAiB,EAAE,cAAc,EACjC,UAAU,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,EAC5B,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAEpC,oBAAC,iBAAiB,QACf,IAAI,CAAC,CAAC,CAAC,CACN,oBAAC,KAAK,IACJ,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,IAAI,iBAAiB,EAAE,EAAE,EAChF,GAAG,EAAE,IAAI,GACT,CACH,CAAC,CAAC,CAAC,CACF,oBAAC,UAAU,IAAC,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAG,KAAK,CAAc,CAC/E,CACiB;YAEpB,oBAAC,GAAG,IAAC,SAAS,EAAC,MAAM,EAAC,QAAQ,EAAE,YAAY;gBAC1C,oBAAC,aAAa;oBACZ,oBAAC,KAAK,IAAC,OAAO,EAAE,CAAC;wBACf,oBAAC,UAAU,IAAC,OAAO,EAAC,IAAI,IAAE,CAAC,CAAC,qBAAqB,CAAC,CAAc;wBAChE,oBAAC,UAAU,IAAC,KAAK,EAAC,gBAAgB,EAAC,OAAO,EAAC,OAAO,IAC/C,CAAC,CAAC,gCAAgC,CAAC,CACzB;wBAEZ,UAAU,IAAI,oBAAC,KAAK,IAAC,QAAQ,EAAC,OAAO,IAAE,UAAU,CAAS;wBAE1D,KAAK,IAAI,CAAC,UAAU,IAAI,oBAAC,KAAK,IAAC,QAAQ,EAAC,OAAO,IAAE,KAAK,CAAS;wBAE/D,CAAC,UAAU,IAAI,CACd;4BACE,oBAAC,SAAS,IACR,SAAS,QACT,QAAQ,QACR,KAAK,EAAC,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,EAAE,EAC1D,KAAK,EAAE,CAAC,CAAC,cAAc,CAAC,EACxB,IAAI,EAAC,UAAU,EACf,IAAI,EAAC,UAAU,EACf,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAC5C;4BACF,oBAAC,SAAS,IACR,SAAS,QACT,QAAQ,QACR,KAAK,EAAC,WAAW,EACjB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,EAAE,YAAY,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC,EAAE,EAClE,KAAK,EAAE,CAAC,CAAC,sBAAsB,CAAC,EAChC,IAAI,EAAC,iBAAiB,EACtB,IAAI,EAAC,UAAU,EACf,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GACnD,CACD,CACJ,CACK,CACM;gBAEhB,oBAAC,aAAa,IACZ,EAAE,EAAE;wBACF,EAAE,EAAE,CAAC;wBACL,EAAE,EAAE,CAAC;qBACN,IAEA,CAAC,UAAU,IAAI,CACd,oBAAC,aAAa,kBACD,gBAAgB,EAC3B,KAAK,EAAC,SAAS,EACf,QAAQ,EAAE,CAAC,KAAK,EAChB,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EACtB,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,WAAW,IAElB,CAAC,CAAC,gBAAgB,CAAC,CACN,CACjB,CACa,CACZ,CACO,CACP,CACX,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -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[]>;
|
|
@@ -24,6 +25,7 @@ export interface ProductProperty {
|
|
|
24
25
|
name: string;
|
|
25
26
|
title: string;
|
|
26
27
|
type: string;
|
|
28
|
+
required: boolean;
|
|
27
29
|
min_length?: number;
|
|
28
30
|
min_value?: number;
|
|
29
31
|
max_value?: number;
|
|
@@ -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
|
};
|
|
@@ -51,6 +51,18 @@ export const ProductPropertiesCard: React.FC<ProductPropertiesCardProps> = ({
|
|
|
51
51
|
|
|
52
52
|
productPropertiesList.map((prop) => {
|
|
53
53
|
switch (prop.type) {
|
|
54
|
+
case "string": {
|
|
55
|
+
if (!prop.required && values[prop.name] == "") {
|
|
56
|
+
delete values[prop.name];
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "integer": {
|
|
61
|
+
if (!prop.required && values[prop.name] == "") {
|
|
62
|
+
delete values[prop.name];
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
54
66
|
case "array": {
|
|
55
67
|
values[prop.name] =
|
|
56
68
|
typeof values[prop.name] === "string"
|
|
@@ -23,7 +23,7 @@ export const ProductPropertyField: React.FC<ProductPropertyFieldProps> = ({
|
|
|
23
23
|
<CardFieldText
|
|
24
24
|
formName={formName ?? property.name}
|
|
25
25
|
label={property.title}
|
|
26
|
-
required={property.
|
|
26
|
+
required={property.required}
|
|
27
27
|
value={currentValue}
|
|
28
28
|
/>
|
|
29
29
|
);
|
|
@@ -37,7 +37,7 @@ export const ProductPropertyField: React.FC<ProductPropertyFieldProps> = ({
|
|
|
37
37
|
label={property.title}
|
|
38
38
|
max={property.max_value}
|
|
39
39
|
min={property.min_value}
|
|
40
|
-
required={property.
|
|
40
|
+
required={property.required}
|
|
41
41
|
value={Number.isNaN(currentValue) ? undefined : currentValue}
|
|
42
42
|
/>
|
|
43
43
|
);
|
|
@@ -54,6 +54,7 @@ export const ProductPropertyField: React.FC<ProductPropertyFieldProps> = ({
|
|
|
54
54
|
fallback={"—"}
|
|
55
55
|
formName={formName ?? property.name}
|
|
56
56
|
label={property.title}
|
|
57
|
+
required={property.required}
|
|
57
58
|
value={(currentValue ?? []).map((val: ProductPropertyValue) => ({
|
|
58
59
|
id: val as string,
|
|
59
60
|
label: val as string,
|
|
@@ -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>
|
|
@@ -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
|
|
|
10
11
|
export type ProductPropertyValue =
|
|
@@ -39,6 +40,7 @@ export interface ProductProperty {
|
|
|
39
40
|
name: string;
|
|
40
41
|
title: string;
|
|
41
42
|
type: string;
|
|
43
|
+
required: boolean;
|
|
42
44
|
|
|
43
45
|
min_length?: number;
|
|
44
46
|
min_value?: number;
|