Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cod-client-astro/locales/ar/products.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"status": {
"available": "متاح",
"out_of_stock": "غير متوفر",
"low_stock": "مخزون منخفض"
"low_stock": "مخزون منخفض",
"hidden_from_store": "مخفي من المتجر"
},
"stock": {
"in_stock": "في المخزون",
Expand Down Expand Up @@ -141,6 +142,8 @@
"threshold_label": "حد التنبيه",
"threshold_hint": "تنبيه عند وصول المخزون لهذا الحد",
"track_stock_hint": "مراقبة مستويات المخزون تلقائياً",
"show_in_store_label": "إظهار في المتجر",
"show_in_store_hint": "المنتجات المخفية لا تظهر في قائمة المتجر ولا في صفحتها — لكن صفحات الهبوط الخاصة بها تظل تعمل كالمعتاد.",
"bulk_fill": "ملء جماعي",
"bulk_price_placeholder": "السعر",
"bulk_price_apply": "تطبيق السعر",
Expand Down
5 changes: 4 additions & 1 deletion cod-client-astro/locales/en/products.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"status": {
"available": "Available",
"out_of_stock": "Out of Stock",
"low_stock": "Low Stock"
"low_stock": "Low Stock",
"hidden_from_store": "Hidden from store"
},
"stock": {
"in_stock": "In Stock",
Expand Down Expand Up @@ -141,6 +142,8 @@
"threshold_label": "Alert Threshold",
"threshold_hint": "Alert when stock drops to this level",
"track_stock_hint": "Monitor inventory levels automatically",
"show_in_store_label": "Show in store",
"show_in_store_hint": "Hidden products don't appear in the storefront catalog or product page — their landing pages keep selling as normal.",
"bulk_fill": "Bulk fill",
"bulk_price_placeholder": "Price",
"bulk_price_apply": "Set price",
Expand Down
5 changes: 4 additions & 1 deletion cod-client-astro/locales/fr/products.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"status": {
"available": "Disponible",
"out_of_stock": "Rupture de stock",
"low_stock": "Stock faible"
"low_stock": "Stock faible",
"hidden_from_store": "Masqué de la boutique"
},
"stock": {
"in_stock": "En stock",
Expand Down Expand Up @@ -141,6 +142,8 @@
"threshold_label": "Seuil d'alerte",
"threshold_hint": "Alerte lorsque le stock descend à ce niveau",
"track_stock_hint": "Surveiller automatiquement les niveaux d'inventaire",
"show_in_store_label": "Afficher dans la boutique",
"show_in_store_hint": "Les produits masqués n'apparaissent ni dans le catalogue ni sur leur page — leurs pages de destination continuent de vendre normalement.",
"bulk_fill": "Remplissage groupé",
"bulk_price_placeholder": "Prix",
"bulk_price_apply": "Appliquer le prix",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ export function ProductDetail({ productId }: { productId: string }) {
<div className="min-w-0 flex-1 space-y-3">
<div className="flex flex-wrap items-center gap-2">
<ProductStatusBadge status={product.status} />
{product.showInStore === false && (
<Badge tone="neutral">{t("status.hidden_from_store")}</Badge>
)}
{product.sku && (
<span className="rounded-lg border border-border bg-muted/30 px-2 py-0.5 font-mono text-[10px] font-bold uppercase text-muted-foreground">
{product.sku}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export function ProductForm({ productId }: { productId?: string }) {
const [costPrice, setCostPrice] = useState("");
const [status, setStatus] = useState<ProductStatus>("ACTIVE");
const [trackInventory, setTrackInventory] = useState(true);
const [showInStore, setShowInStore] = useState(true);
const [inventory, setInventory] = useState("0");
const [lowStockThreshold, setLowStockThreshold] = useState("5");

Expand Down Expand Up @@ -168,6 +169,7 @@ export function ProductForm({ productId }: { productId?: string }) {
setCostPrice(product.costPrice ? String(product.costPrice) : "");
setStatus(product.status);
setTrackInventory(product.trackInventory);
setShowInStore(product.showInStore);
setInventory(String(product.inventory));
setLowStockThreshold(String(product.lowStockThreshold ?? 5));
if (product.hasVariants) {
Expand Down Expand Up @@ -304,6 +306,7 @@ export function ProductForm({ productId }: { productId?: string }) {
costPrice: costPrice ? Math.round(Number(costPrice)) : undefined,
status,
trackInventory,
showInStore,
...(editing
? {}
: { inventory: hasVariants ? 0 : Number(inventory) || 0 }),
Expand Down Expand Up @@ -508,6 +511,8 @@ export function ProductForm({ productId }: { productId?: string }) {
setLowStockThreshold={setLowStockThreshold}
trackInventory={trackInventory}
setTrackInventory={setTrackInventory}
showInStore={showInStore}
setShowInStore={setShowInStore}
hasVariantsSwitch={hasVariantsSwitch}
editing={editing}
busy={busy}
Expand Down
11 changes: 10 additions & 1 deletion cod-client-astro/src/features/products/components/ProductRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ function ProductStatusBadge({ product }: { product: Product }) {
return <Badge tone="critical">{t("status_options.archived")}</Badge>;
}

function HiddenFromStoreBadge() {
const t = useT("products");
return <Badge tone="neutral">{t("status.hidden_from_store")}</Badge>;
}

function StockValue({ product }: { product: Product }) {
const t = useT("products");
const total = product.totalInventory ?? product.inventory ?? 0;
Expand Down Expand Up @@ -93,7 +98,10 @@ export function ProductDesktopRow({ product, categoryMap, canManage, onDelete }:
</span>
</TableCell>
<TableCell>
<ProductStatusBadge product={product} />
<div className="flex flex-wrap items-center gap-1.5">
<ProductStatusBadge product={product} />
{product.showInStore === false && <HiddenFromStoreBadge />}
</div>
</TableCell>
<TableCell className="text-sm font-semibold tabular-nums">
{formatMoneyValue(product.price, locale)}
Expand Down Expand Up @@ -169,6 +177,7 @@ export function ProductMobileCard({ product, categoryMap, canManage, onDelete }:
)}
<div className="mt-2 flex flex-wrap items-center gap-2">
<ProductStatusBadge product={product} />
{product.showInStore === false && <HiddenFromStoreBadge />}
{category && (
<span className="rounded-full bg-muted px-2 py-0.5 text-[11px] font-semibold text-muted-foreground">
{category.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ interface ProductSettingsCardProps {
setLowStockThreshold: (val: string) => void;
trackInventory: boolean;
setTrackInventory: (val: boolean) => void;
showInStore: boolean;
setShowInStore: (val: boolean) => void;
hasVariantsSwitch: boolean;
editing: boolean;
busy: boolean;
Expand All @@ -27,6 +29,8 @@ export function ProductSettingsCard({
setLowStockThreshold,
trackInventory,
setTrackInventory,
showInStore,
setShowInStore,
hasVariantsSwitch,
editing,
busy,
Expand Down Expand Up @@ -97,6 +101,27 @@ export function ProductSettingsCard({
/>
</label>
</div>
<div className="mt-4">
<label className="flex cursor-pointer items-center justify-between gap-4">
<div>
<p className="text-sm font-semibold text-foreground">
{t("form.show_in_store_label")}
</p>
<p className="mt-0.5 text-xs text-muted-foreground">
{t("form.show_in_store_hint")}
</p>
</div>
<input
type="checkbox"
checked={showInStore}
onChange={(event) =>
setShowInStore(event.currentTarget.checked)
}
disabled={busy}
className="size-5 accent-primary"
/>
</label>
</div>
</Card>
);
}
Loading