bananas-commerce-admin 0.19.5 → 0.19.6

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.
@@ -1,10 +1,26 @@
1
1
  import React from "react";
2
2
  import CancelIcon from "@mui/icons-material/Cancel";
3
3
  import CheckCircleIcon from "@mui/icons-material/CheckCircle";
4
+ import WarningIcon from "@mui/icons-material/Warning";
4
5
  import Chip from "../Chip";
5
6
  // TODO Logic for picking icon
6
- export const CardPill = ({ label, color, icon, size = "small" }) => {
7
- return (React.createElement(Chip, { color: color ?? "success", icon: icon ?? (color === "success" ? React.createElement(CheckCircleIcon, null) : React.createElement(CancelIcon, null)), label: label, size: size }));
7
+ export const CardPill = ({ label, color, icon, size = "small", variant, }) => {
8
+ let resolvedIcon;
9
+ if (icon === undefined) {
10
+ if (color === "success") {
11
+ resolvedIcon = React.createElement(CheckCircleIcon, null);
12
+ }
13
+ else if (color === "warning") {
14
+ resolvedIcon = React.createElement(WarningIcon, null);
15
+ }
16
+ else {
17
+ resolvedIcon = React.createElement(CancelIcon, null);
18
+ }
19
+ }
20
+ else {
21
+ resolvedIcon = icon ?? undefined;
22
+ }
23
+ return (React.createElement(Chip, { color: color ?? "success", icon: resolvedIcon, label: label, size: size, variant: variant }));
8
24
  };
9
25
  export default CardPill;
10
26
  //# sourceMappingURL=CardPill.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CardPill.js","sourceRoot":"","sources":["../../../../src/components/Card/CardPill.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,UAAU,MAAM,4BAA4B,CAAC;AACpD,OAAO,eAAe,MAAM,iCAAiC,CAAC;AAI9D,OAAO,IAAI,MAAM,SAAS,CAAC;AAQ3B,8BAA8B;AAC9B,MAAM,CAAC,MAAM,QAAQ,GAA4B,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,EAAE,EAAE,EAAE;IAC1F,OAAO,CACL,oBAAC,IAAI,IACH,KAAK,EAAE,KAAK,IAAI,SAAS,EACzB,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAC,eAAe,OAAG,CAAC,CAAC,CAAC,oBAAC,UAAU,OAAG,CAAC,EAC1E,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,GACV,CACH,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"CardPill.js","sourceRoot":"","sources":["../../../../src/components/Card/CardPill.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,UAAU,MAAM,4BAA4B,CAAC;AACpD,OAAO,eAAe,MAAM,iCAAiC,CAAC;AAC9D,OAAO,WAAW,MAAM,6BAA6B,CAAC;AAItD,OAAO,IAAI,MAAM,SAAS,CAAC;AAS3B,8BAA8B;AAC9B,MAAM,CAAC,MAAM,QAAQ,GAA4B,CAAC,EAChD,KAAK,EACL,KAAK,EACL,IAAI,EACJ,IAAI,GAAG,OAAO,EACd,OAAO,GACR,EAAE,EAAE;IACH,IAAI,YAA4C,CAAC;IACjD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,YAAY,GAAG,oBAAC,eAAe,OAAG,CAAC;QACrC,CAAC;aAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/B,YAAY,GAAG,oBAAC,WAAW,OAAG,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,oBAAC,UAAU,OAAG,CAAC;QAChC,CAAC;IACH,CAAC;SAAM,CAAC;QACN,YAAY,GAAG,IAAI,IAAI,SAAS,CAAC;IACnC,CAAC;IAED,OAAO,CACL,oBAAC,IAAI,IACH,KAAK,EAAE,KAAK,IAAI,SAAS,EACzB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,GAChB,CACH,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -8,6 +8,9 @@ export const Chip = styled(MuiChip)(({ theme }) => theme.unstable_sx({
8
8
  ".MuiChip-labelMedium": {
9
9
  pl: 1,
10
10
  },
11
+ ".MuiChip-label": {
12
+ fontWeight: theme.typography.fontWeightRegular,
13
+ },
11
14
  }));
12
15
  export default Chip;
13
16
  //# sourceMappingURL=Chip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Chip.js","sourceRoot":"","sources":["../../../src/components/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAChD,KAAK,CAAC,WAAW,CAAC;IAChB,YAAY,EAAE,CAAC;IACf,qBAAqB,EAAE;QACrB,MAAM,EAAE,EAAE;KACX;IACD,sBAAsB,EAAE;QACtB,EAAE,EAAE,CAAC;KACN;CACF,CAAC,CACH,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"Chip.js","sourceRoot":"","sources":["../../../src/components/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAChD,KAAK,CAAC,WAAW,CAAC;IAChB,YAAY,EAAE,CAAC;IACf,qBAAqB,EAAE;QACrB,MAAM,EAAE,EAAE;KACX;IACD,sBAAsB,EAAE;QACtB,EAAE,EAAE,CAAC;KACN;IACD,gBAAgB,EAAE;QAChB,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB;KAC/C;CACF,CAAC,CACH,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,66 @@
1
+ import React from "react";
2
+ import LocalOfferOutlinedIcon from "@mui/icons-material/LocalOfferOutlined";
3
+ import ReportIcon from "@mui/icons-material/Report";
4
+ import WarningIcon from "@mui/icons-material/Warning";
5
+ import { Grid2 as Grid, Stack, Typography } from "@mui/material";
6
+ import Card from "../../../components/Card";
7
+ import CardContent from "../../../components/Card/CardContent";
8
+ import CardHeader from "../../../components/Card/CardHeader";
9
+ import CardPill from "../../../components/Card/CardPill";
10
+ import Content from "../../../containers/Content";
11
+ const parseStatus = (value) => {
12
+ if (!value) {
13
+ return { codes: [] };
14
+ }
15
+ const trimmed = value.trim();
16
+ const match = /^([^[]+)\[([^\]]*)\]>?$/.exec(trimmed);
17
+ if (!match) {
18
+ return { label: trimmed, codes: [] };
19
+ }
20
+ const [, label, codes] = match;
21
+ return {
22
+ label: label.trim(),
23
+ codes: codes
24
+ .split(",")
25
+ .map((code) => code.trim())
26
+ .filter(Boolean),
27
+ };
28
+ };
29
+ const formatItem = (label, value) => (React.createElement(Stack, { key: label, direction: "row", justifyContent: "space-between", spacing: 2 },
30
+ React.createElement(Typography, { color: "text.secondary", variant: "body2" }, label),
31
+ typeof value === "string" || typeof value === "number" ? (React.createElement(Typography, { variant: "body2" }, value)) : (value)));
32
+ const ItemCard = ({ item }) => {
33
+ const { label: errorLabel, codes: errorCodes } = parseStatus(item.error);
34
+ const { label: warningLabel, codes: warningCodes } = parseStatus(item.warning);
35
+ return (React.createElement(Card, null,
36
+ React.createElement(CardHeader, { title: item.site_code }),
37
+ React.createElement(CardContent, null,
38
+ React.createElement(Stack, { spacing: 1 },
39
+ formatItem("Reference", item.reference),
40
+ formatItem("Name", item.name),
41
+ formatItem("Variant", item.variant || "—"),
42
+ formatItem("Price", item.base_price !== item.price ? (React.createElement(Stack, { alignItems: "center", direction: "row", spacing: 1 },
43
+ React.createElement(Typography, { color: "text.disabled", sx: { textDecoration: "line-through" }, variant: "body2" },
44
+ item.base_price,
45
+ " ",
46
+ item.currency),
47
+ React.createElement(LocalOfferOutlinedIcon, { color: "error", fontSize: "small" }),
48
+ React.createElement(Typography, { color: "error", variant: "body2" },
49
+ item.price,
50
+ " ",
51
+ item.currency))) : (`${item.price} ${item.currency}`)),
52
+ React.createElement(Stack, { alignItems: "center", alignSelf: "flex-start", direction: "row", flexWrap: "wrap", gap: 1 },
53
+ errorLabel && React.createElement(CardPill, { color: "error", icon: React.createElement(ReportIcon, null), label: errorLabel }),
54
+ errorCodes.map((code) => (React.createElement(CardPill, { key: `error-${code}`, color: "error", icon: null, label: code, variant: "outlined" }))),
55
+ warningLabel && (React.createElement(CardPill, { color: "warning", icon: React.createElement(WarningIcon, null), label: warningLabel })),
56
+ warningCodes.map((code) => (React.createElement(CardPill, { key: `warning-${code}`, color: "warning", icon: null, label: code, variant: "outlined" }))),
57
+ React.createElement(CardPill, { color: item.is_available ? "success" : "warning", label: item.is_available ? "Available" : "Unavailable" }))))));
58
+ };
59
+ const SiteAvailability = ({ data }) => {
60
+ const items = data.items ?? [];
61
+ return (React.createElement(Content, { layout: "fullWidth" }, items.length > 0 ? (React.createElement(Grid, { container: true, columns: 12, spacing: 2, width: "100%" }, items.map((item) => (React.createElement(Grid, { key: `${item.site_code}-${item.reference}`, size: { xs: 12, md: 4 } },
62
+ React.createElement(Stack, { spacing: 2 },
63
+ React.createElement(ItemCard, { item: item }))))))) : (React.createElement(Typography, { color: "text.secondary", variant: "body2" }, "No items found"))));
64
+ };
65
+ export default SiteAvailability;
66
+ //# sourceMappingURL=SiteAvailability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SiteAvailability.js","sourceRoot":"","sources":["../../../../../src/extensions/catalog/contrib/SiteAvailability.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
+ import StorefrontIcon from "@mui/icons-material/Storefront";
1
2
  import WorkspacesIcon from "../../assets/symbols/Workspaces";
2
3
  export * from "./types/article";
4
+ export * from "./types/contrib";
3
5
  const routes = {
4
6
  article: {
5
7
  create: { page: async () => (await import("./pages/article/create")).default, offline: true },
@@ -26,4 +28,15 @@ export const navigation = {
26
28
  permission: "catalog.view_article",
27
29
  },
28
30
  };
31
+ export const contrib = {
32
+ pos: {
33
+ "catalog:article:detail:items": {
34
+ title: "Availability",
35
+ icon: StorefrontIcon,
36
+ component: async () => (await import("./contrib/SiteAvailability")).default,
37
+ variant: "tab",
38
+ permission: "catalog.view_article",
39
+ },
40
+ },
41
+ };
29
42
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extensions/catalog/index.tsx"],"names":[],"mappings":"AAEA,OAAO,cAAc,MAAM,iCAAiC,CAAC;AAI7D,cAAc,iBAAiB,CAAC;AAEhC,MAAM,MAAM,GAYR;IACF,OAAO,EAAE;QACP,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;QAC7F,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,EAAE;QAC9E,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,EAAE;KAC3E;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAoB;IACrC,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;QACf,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAElE,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YACjB,OAAO;gBACL,IAAI,EAAE,IAAI,EAAE;gBACZ,GAAG,GAAG;aACP,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAwB;IAC7C,sBAAsB,EAAE;QACtB,IAAI,EAAE,cAAc;QACpB,UAAU,EAAE,sBAAsB;KACnC;CACO,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/extensions/catalog/index.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,gCAAgC,CAAC;AAI5D,OAAO,cAAc,MAAM,iCAAiC,CAAC;AAI7D,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAEhC,MAAM,MAAM,GAYR;IACF,OAAO,EAAE;QACP,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;QAC7F,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,OAAO,EAAE;QAC9E,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,EAAE;KAC3E;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAoB;IACrC,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;QACf,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAElE,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YACjB,OAAO;gBACL,IAAI,EAAE,IAAI,EAAE;gBACZ,GAAG,GAAG;aACP,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAwB;IAC7C,sBAAsB,EAAE;QACtB,IAAI,EAAE,cAAc;QACpB,UAAU,EAAE,sBAAsB;KACnC;CACO,CAAC;AAEX,MAAM,CAAC,MAAM,OAAO,GAAwC;IAC1D,GAAG,EAAE;QACH,8BAA8B,EAAE;YAC9B,KAAK,EAAE,cAAc;YACrB,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC,CAAC,OAAO;YAC3E,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,sBAAsB;SACnC;KACF;CACO,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contrib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contrib.js","sourceRoot":"","sources":["../../../../../src/extensions/catalog/types/contrib.ts"],"names":[],"mappings":""}
@@ -4,6 +4,7 @@ import { OverridableStringUnion } from "@mui/types";
4
4
  import { Pill } from "./shared";
5
5
  export interface CardPillProps extends Pill {
6
6
  size?: OverridableStringUnion<"small" | "medium", ChipPropsSizeOverrides>;
7
+ variant?: "filled" | "outlined";
7
8
  }
8
9
  export declare const CardPill: React.FC<CardPillProps>;
9
10
  export default CardPill;
@@ -6,7 +6,7 @@ export interface FormOption {
6
6
  export interface Pill {
7
7
  label: string;
8
8
  color?: "success" | "error" | "warning" | "info" | "default";
9
- icon?: React.ReactElement;
9
+ icon?: React.ReactElement | null;
10
10
  }
11
11
  export interface CardFieldBaseProps extends React.PropsWithChildren {
12
12
  formName: string;
@@ -0,0 +1,4 @@
1
+ import { ContribComponent } from "../../../types";
2
+ import { SiteItemsResponse } from "../types/contrib";
3
+ declare const SiteAvailability: ContribComponent<SiteItemsResponse>;
4
+ export default SiteAvailability;
@@ -1,5 +1,7 @@
1
1
  import { RouterExtension } from "../../router/Router";
2
- import { NavigationOverrides } from "../../types";
2
+ import { ContribComponentMap, NavigationOverrides } from "../../types";
3
3
  export * from "./types/article";
4
+ export * from "./types/contrib";
4
5
  export declare const router: RouterExtension;
5
6
  export declare const navigation: NavigationOverrides;
7
+ export declare const contrib: Record<string, ContribComponentMap>;
@@ -0,0 +1,15 @@
1
+ export interface SiteItem {
2
+ site_code: string;
3
+ currency: string;
4
+ reference: string;
5
+ name: string;
6
+ variant: string;
7
+ base_price: string;
8
+ price: string;
9
+ is_available: boolean;
10
+ error?: string | null;
11
+ warning?: string | null;
12
+ }
13
+ export interface SiteItemsResponse {
14
+ items: SiteItem[];
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bananas-commerce-admin",
3
- "version": "0.19.5",
3
+ "version": "0.19.6",
4
4
  "description": "What's this, an admin for apes?",
5
5
  "keywords": [
6
6
  "admin",
@@ -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 WarningIcon from "@mui/icons-material/Warning";
5
6
  import { ChipPropsSizeOverrides } from "@mui/material/Chip";
6
7
  import { OverridableStringUnion } from "@mui/types";
7
8
 
@@ -11,16 +12,37 @@ import { Pill } from "./shared";
11
12
 
12
13
  export interface CardPillProps extends Pill {
13
14
  size?: OverridableStringUnion<"small" | "medium", ChipPropsSizeOverrides>;
15
+ variant?: "filled" | "outlined";
14
16
  }
15
17
 
16
18
  // TODO Logic for picking icon
17
- export const CardPill: React.FC<CardPillProps> = ({ label, color, icon, size = "small" }) => {
19
+ export const CardPill: React.FC<CardPillProps> = ({
20
+ label,
21
+ color,
22
+ icon,
23
+ size = "small",
24
+ variant,
25
+ }) => {
26
+ let resolvedIcon: React.ReactElement | undefined;
27
+ if (icon === undefined) {
28
+ if (color === "success") {
29
+ resolvedIcon = <CheckCircleIcon />;
30
+ } else if (color === "warning") {
31
+ resolvedIcon = <WarningIcon />;
32
+ } else {
33
+ resolvedIcon = <CancelIcon />;
34
+ }
35
+ } else {
36
+ resolvedIcon = icon ?? undefined;
37
+ }
38
+
18
39
  return (
19
40
  <Chip
20
41
  color={color ?? "success"}
21
- icon={icon ?? (color === "success" ? <CheckCircleIcon /> : <CancelIcon />)}
42
+ icon={resolvedIcon}
22
43
  label={label}
23
44
  size={size}
45
+ variant={variant}
24
46
  />
25
47
  );
26
48
  };
@@ -8,7 +8,7 @@ export interface FormOption {
8
8
  export interface Pill {
9
9
  label: string;
10
10
  color?: "success" | "error" | "warning" | "info" | "default";
11
- icon?: React.ReactElement;
11
+ icon?: React.ReactElement | null;
12
12
  }
13
13
 
14
14
  export interface CardFieldBaseProps extends React.PropsWithChildren {
@@ -10,6 +10,9 @@ export const Chip = styled(MuiChip)(({ theme }) =>
10
10
  ".MuiChip-labelMedium": {
11
11
  pl: 1,
12
12
  },
13
+ ".MuiChip-label": {
14
+ fontWeight: theme.typography.fontWeightRegular,
15
+ },
13
16
  }),
14
17
  );
15
18
 
@@ -0,0 +1,138 @@
1
+ import React from "react";
2
+
3
+ import LocalOfferOutlinedIcon from "@mui/icons-material/LocalOfferOutlined";
4
+ import ReportIcon from "@mui/icons-material/Report";
5
+ import WarningIcon from "@mui/icons-material/Warning";
6
+ import { Grid2 as Grid, Stack, Typography } from "@mui/material";
7
+
8
+ import Card from "../../../components/Card";
9
+ import CardContent from "../../../components/Card/CardContent";
10
+ import CardHeader from "../../../components/Card/CardHeader";
11
+ import CardPill from "../../../components/Card/CardPill";
12
+ import Content from "../../../containers/Content";
13
+ import { ContribComponent } from "../../../types";
14
+ import { SiteItem, SiteItemsResponse } from "../types/contrib";
15
+
16
+ const parseStatus = (value: string | null | undefined): { label?: string; codes: string[] } => {
17
+ if (!value) {
18
+ return { codes: [] };
19
+ }
20
+ const trimmed = value.trim();
21
+ const match = /^([^[]+)\[([^\]]*)\]>?$/.exec(trimmed);
22
+ if (!match) {
23
+ return { label: trimmed, codes: [] };
24
+ }
25
+ const [, label, codes] = match;
26
+ return {
27
+ label: label.trim(),
28
+ codes: codes
29
+ .split(",")
30
+ .map((code) => code.trim())
31
+ .filter(Boolean),
32
+ };
33
+ };
34
+
35
+ const formatItem = (label: string, value: React.ReactNode) => (
36
+ <Stack key={label} direction="row" justifyContent="space-between" spacing={2}>
37
+ <Typography color="text.secondary" variant="body2">
38
+ {label}
39
+ </Typography>
40
+ {typeof value === "string" || typeof value === "number" ? (
41
+ <Typography variant="body2">{value}</Typography>
42
+ ) : (
43
+ value
44
+ )}
45
+ </Stack>
46
+ );
47
+
48
+ const ItemCard: React.FC<{ item: SiteItem }> = ({ item }) => {
49
+ const { label: errorLabel, codes: errorCodes } = parseStatus(item.error);
50
+ const { label: warningLabel, codes: warningCodes } = parseStatus(item.warning);
51
+
52
+ return (
53
+ <Card>
54
+ <CardHeader title={item.site_code} />
55
+ <CardContent>
56
+ <Stack spacing={1}>
57
+ {formatItem("Reference", item.reference)}
58
+ {formatItem("Name", item.name)}
59
+ {formatItem("Variant", item.variant || "—")}
60
+ {formatItem(
61
+ "Price",
62
+ item.base_price !== item.price ? (
63
+ <Stack alignItems="center" direction="row" spacing={1}>
64
+ <Typography
65
+ color="text.disabled"
66
+ sx={{ textDecoration: "line-through" }}
67
+ variant="body2"
68
+ >
69
+ {item.base_price} {item.currency}
70
+ </Typography>
71
+ <LocalOfferOutlinedIcon color="error" fontSize="small" />
72
+ <Typography color="error" variant="body2">
73
+ {item.price} {item.currency}
74
+ </Typography>
75
+ </Stack>
76
+ ) : (
77
+ `${item.price} ${item.currency}`
78
+ ),
79
+ )}
80
+ <Stack alignItems="center" alignSelf="flex-start" direction="row" flexWrap="wrap" gap={1}>
81
+ {errorLabel && <CardPill color="error" icon={<ReportIcon />} label={errorLabel} />}
82
+ {errorCodes.map((code) => (
83
+ <CardPill
84
+ key={`error-${code}`}
85
+ color="error"
86
+ icon={null}
87
+ label={code}
88
+ variant="outlined"
89
+ />
90
+ ))}
91
+ {warningLabel && (
92
+ <CardPill color="warning" icon={<WarningIcon />} label={warningLabel} />
93
+ )}
94
+ {warningCodes.map((code) => (
95
+ <CardPill
96
+ key={`warning-${code}`}
97
+ color="warning"
98
+ icon={null}
99
+ label={code}
100
+ variant="outlined"
101
+ />
102
+ ))}
103
+ <CardPill
104
+ color={item.is_available ? "success" : "warning"}
105
+ label={item.is_available ? "Available" : "Unavailable"}
106
+ />
107
+ </Stack>
108
+ </Stack>
109
+ </CardContent>
110
+ </Card>
111
+ );
112
+ };
113
+
114
+ const SiteAvailability: ContribComponent<SiteItemsResponse> = ({ data }) => {
115
+ const items = data.items ?? [];
116
+
117
+ return (
118
+ <Content layout="fullWidth">
119
+ {items.length > 0 ? (
120
+ <Grid container columns={12} spacing={2} width="100%">
121
+ {items.map((item) => (
122
+ <Grid key={`${item.site_code}-${item.reference}`} size={{ xs: 12, md: 4 }}>
123
+ <Stack spacing={2}>
124
+ <ItemCard item={item} />
125
+ </Stack>
126
+ </Grid>
127
+ ))}
128
+ </Grid>
129
+ ) : (
130
+ <Typography color="text.secondary" variant="body2">
131
+ No items found
132
+ </Typography>
133
+ )}
134
+ </Content>
135
+ );
136
+ };
137
+
138
+ export default SiteAvailability;
@@ -1,10 +1,13 @@
1
+ import StorefrontIcon from "@mui/icons-material/Storefront";
2
+
1
3
  import { OpenAPI } from "openapi-types";
2
4
 
3
5
  import WorkspacesIcon from "../../assets/symbols/Workspaces";
4
6
  import { RouterExtension } from "../../router/Router";
5
- import { NavigationOverrides, PageComponent } from "../../types";
7
+ import { ContribComponentMap, NavigationOverrides, PageComponent } from "../../types";
6
8
 
7
9
  export * from "./types/article";
10
+ export * from "./types/contrib";
8
11
 
9
12
  const routes: Record<
10
13
  string,
@@ -48,3 +51,15 @@ export const navigation: NavigationOverrides = {
48
51
  permission: "catalog.view_article",
49
52
  },
50
53
  } as const;
54
+
55
+ export const contrib: Record<string, ContribComponentMap> = {
56
+ pos: {
57
+ "catalog:article:detail:items": {
58
+ title: "Availability",
59
+ icon: StorefrontIcon,
60
+ component: async () => (await import("./contrib/SiteAvailability")).default,
61
+ variant: "tab",
62
+ permission: "catalog.view_article",
63
+ },
64
+ },
65
+ } as const;
@@ -0,0 +1,16 @@
1
+ export interface SiteItem {
2
+ site_code: string;
3
+ currency: string;
4
+ reference: string;
5
+ name: string;
6
+ variant: string;
7
+ base_price: string;
8
+ price: string;
9
+ is_available: boolean;
10
+ error?: string | null;
11
+ warning?: string | null;
12
+ }
13
+
14
+ export interface SiteItemsResponse {
15
+ items: SiteItem[];
16
+ }