chore(dashboard): text changes and fixes (#7925)

- Improvements to existing texts
- Add subtitles to sections where useful.
- Added the ability to edit the message shown in a list when no records are found + change the message where necessary
- Change documentation link to `https://docs.medusajs.com/v2`.
This commit is contained in:
Shahed Nasser authored and GitHub committed 2024-07-05 12:14:10 +00:00
1 parent f4dd390ab1
commit eafa3560ae
41 files changed
+360 -132

No files matched your search

@@ -3,7 +3,7 @@ import { Button, Text, clx } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
type NoResultsProps = { export type NoResultsProps = {
title?: string title?: string
message?: string message?: string
className?: string className?: string
@@ -319,11 +319,7 @@ const LoggedInUser = () => {
<Profile /> <Profile />
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item asChild> <DropdownMenu.Item asChild>
<Link <Link to="https://docs.medusajs.com/v2" target="_blank">
// TODO change link once docs are public
to="https://medusa-docs-v2-git-docs-v2-medusajs.vercel.app/"
target="_blank"
>
<BookOpen className="text-ui-fg-subtle mr-2" /> <BookOpen className="text-ui-fg-subtle mr-2" />
Documentation Documentation
</Link> </Link>
@@ -1,6 +1,6 @@
import { clx } from "@medusajs/ui" import { clx } from "@medusajs/ui"
import { memo } from "react" import { memo } from "react"
import { NoRecords } from "../../common/empty-table-content" import { NoRecords, NoResultsProps } from "../../common/empty-table-content"
import { TableSkeleton } from "../../common/skeleton" import { TableSkeleton } from "../../common/skeleton"
import { DataTableQuery, DataTableQueryProps } from "./data-table-query" import { DataTableQuery, DataTableQueryProps } from "./data-table-query"
import { DataTableRoot, DataTableRootProps } from "./data-table-root" import { DataTableRoot, DataTableRootProps } from "./data-table-root"
@@ -11,6 +11,7 @@ interface DataTableProps<TData>
isLoading?: boolean isLoading?: boolean
pageSize: number pageSize: number
queryObject?: Record<string, any> queryObject?: Record<string, any>
noRecords?: Pick<NoResultsProps, "title" | "message">
} }
// Maybe we should use the memoized version of DataTableRoot // Maybe we should use the memoized version of DataTableRoot
@@ -32,6 +33,7 @@ export const DataTable = <TData,>({
pageSize, pageSize,
isLoading = false, isLoading = false,
layout = "fit", layout = "fit",
noRecords: noRecordsProps = {},
}: DataTableProps<TData>) => { }: DataTableProps<TData>) => {
if (isLoading) { if (isLoading) {
return ( return (
@@ -57,6 +59,7 @@ export const DataTable = <TData,>({
className={clx({ className={clx({
"flex h-full flex-col overflow-hidden": layout === "fill", "flex h-full flex-col overflow-hidden": layout === "fill",
})} })}
{...noRecordsProps}
/> />
) )
} }
@@ -28,7 +28,7 @@ export const usePromotionTableColumns = () => {
columnHelper.display({ columnHelper.display({
id: "method", id: "method",
header: () => <TextHeader text={t("promotions.fields.method")} />, header: () => <TextHeader text={t("promotions.fields.campaign")} />,
cell: ({ row }) => { cell: ({ row }) => {
const text = row.original.is_automatic const text = row.original.is_automatic
? "Automatic" ? "Automatic"
@@ -47,8 +47,8 @@
"noSearchResultsFor": "No search results for <0>'{{query}}'</0>", "noSearchResultsFor": "No search results for <0>'{{query}}'</0>",
"noRecordsTitle": "No records", "noRecordsTitle": "No records",
"noRecordsMessage": "There are no records to show", "noRecordsMessage": "There are no records to show",
"unsavedChangesTitle": "Are you sure you want to leave this page?", "unsavedChangesTitle": "Are you sure you want to leave this form?",
"unsavedChangesDescription": "You have unsaved changes that will be lost if you leave this page.", "unsavedChangesDescription": "You have unsaved changes that will be lost if you exit this form.",
"includesTaxTooltip": "Enter the total amount including tax. The net amount excluding tax will be automatically calculated and saved." "includesTaxTooltip": "Enter the total amount including tax. The net amount excluding tax will be automatically calculated and saved."
}, },
"validation": { "validation": {
@@ -205,6 +205,9 @@
}, },
"products": { "products": {
"domain": "Products", "domain": "Products",
"list": {
"noRecordsMessage": "Create your first product to start selling."
},
"create": { "create": {
"header": "General", "header": "General",
"tabs": { "tabs": {
@@ -219,14 +222,14 @@
}, },
"inventory": { "inventory": {
"heading": "Inventory kits", "heading": "Inventory kits",
"label": "Inventory kit", "label": "Add inventory items to the variant's inventory kit.",
"itemPlaceholder": "Select inventory item", "itemPlaceholder": "Select inventory item",
"quantityPlaceholder": "How many of these are needed for the kit?" "quantityPlaceholder": "How many of these are needed for the kit?"
}, },
"variants": { "variants": {
"header": "Variants", "header": "Variants",
"subHeadingTitle": "Yes, this is a product with variants", "subHeadingTitle": "Yes, this is a product with variants",
"subHeadingDescription": "When unchecked we will create a default variant for you", "subHeadingDescription": "When unchecked, we will create a default variant for you",
"optionTitle": { "optionTitle": {
"placeholder": "Size" "placeholder": "Size"
}, },
@@ -235,7 +238,7 @@
}, },
"productVariants": { "productVariants": {
"label": "Product variants", "label": "Product variants",
"hint": "This ranking will affect how the variants are ranked in your frontend.", "hint": "This ranking will affect the variants' order in your storefront.",
"alert": "Add options to create variants." "alert": "Add options to create variants."
}, },
"productOptions": { "productOptions": {
@@ -273,7 +276,7 @@
"action": "Add media" "action": "Add media"
} }
}, },
"discountableHint": "When unchecked discounts will not be applied to this product.", "discountableHint": "When unchecked, discounts will not be applied to this product.",
"noSalesChannels": "Not available in any sales channels", "noSalesChannels": "Not available in any sales channels",
"variantCount_one": "{{count}} variant", "variantCount_one": "{{count}} variant",
"variantCount_other": "{{count}} variants", "variantCount_other": "{{count}} variants",
@@ -302,7 +305,7 @@
}, },
"discountable": { "discountable": {
"label": "Discountable", "label": "Discountable",
"hint": "When unchecked discounts will not be applied to this product" "hint": "When unchecked, discounts will not be applied to this product"
}, },
"type": { "type": {
"label": "Type" "label": "Type"
@@ -318,7 +321,7 @@
}, },
"sales_channels": { "sales_channels": {
"label": "Sales channels", "label": "Sales channels",
"hint": "This product will only be available in the default sales channel if left untouched" "hint": "This product will only be available in the default sales channel if left untouched."
}, },
"countryOrigin": { "countryOrigin": {
"label": "Country of origin" "label": "Country of origin"
@@ -385,9 +388,9 @@
"header": "Stock & Inventory", "header": "Stock & Inventory",
"editItemDetails": "Edit item details", "editItemDetails": "Edit item details",
"manageInventoryLabel": "Manage inventory", "manageInventoryLabel": "Manage inventory",
"manageInventoryHint": "When enabled the inventory level will be regulated when orders and returns are created.", "manageInventoryHint": "When enabled, we'll change the inventory quantity for you when orders and returns are created.",
"allowBackordersLabel": "Allow backorders", "allowBackordersLabel": "Allow backorders",
"allowBackordersHint": "When enabled the variant can be sold even if the inventory level is below zero.", "allowBackordersHint": "When enabled, customers can purchase the variant even if there's no available quantity.",
"toast": { "toast": {
"levelsBatch": "Inventory levels updated.", "levelsBatch": "Inventory levels updated.",
"update": "Inventory item updated successfully.", "update": "Inventory item updated successfully.",
@@ -430,6 +433,7 @@
}, },
"collections": { "collections": {
"domain": "Collections", "domain": "Collections",
"subtitle": "Organize products into collections.",
"createCollection": "Create Collection", "createCollection": "Create Collection",
"createCollectionHint": "Create a new collection to organize your products.", "createCollectionHint": "Create a new collection to organize your products.",
"editCollection": "Edit Collection", "editCollection": "Edit Collection",
@@ -437,16 +441,22 @@
"deleteWarning": "You are about to delete the collection {{title}}. This action cannot be undone.", "deleteWarning": "You are about to delete the collection {{title}}. This action cannot be undone.",
"removeSingleProductWarning": "You are about to remove the product {{title}} from the collection. This action cannot be undone.", "removeSingleProductWarning": "You are about to remove the product {{title}} from the collection. This action cannot be undone.",
"removeProductsWarning_one": "You are about to remove {{count}} product from the collection. This action cannot be undone.", "removeProductsWarning_one": "You are about to remove {{count}} product from the collection. This action cannot be undone.",
"removeProductsWarning_other": "You are about to remove {{count}} products from the collection. This action cannot be undone." "removeProductsWarning_other": "You are about to remove {{count}} products from the collection. This action cannot be undone.",
"products": {
"list": {
"noRecordsMessage": "There are no products in the collection."
}
}
}, },
"categories": { "categories": {
"domain": "Categories", "domain": "Categories",
"subtitle": "Organize products into categories, and manage those categories' ranking and hierarchy.",
"create": { "create": {
"header": "Create Category", "header": "Create Category",
"hint": "Create a new category to organize your products.", "hint": "Create a new category to organize your products.",
"tabs": { "tabs": {
"details": "Details", "details": "Details",
"organize": "Organize" "organize": "Organize Ranking"
}, },
"successToast": "Category {{name}} was successfully created." "successToast": "Category {{name}} was successfully created."
}, },
@@ -465,6 +475,9 @@
"confirmation_other": "You are about to remove {{count}} products from the category. This action cannot be undone.", "confirmation_other": "You are about to remove {{count}} products from the category. This action cannot be undone.",
"successToast_one": "Removed {{count}} product from the category.", "successToast_one": "Removed {{count}} product from the category.",
"successToast_other": "Removed {{count}} products from the category." "successToast_other": "Removed {{count}} products from the category."
},
"list": {
"noRecordsMessage": "There are no products in the category."
} }
}, },
"organize": { "organize": {
@@ -496,15 +509,16 @@
}, },
"inventory": { "inventory": {
"domain": "Inventory", "domain": "Inventory",
"subtitle": "Manage your inventory items",
"reserved": "Reserved", "reserved": "Reserved",
"available": "Available", "available": "Available",
"locationLevels": "Location levels", "locationLevels": "Locations",
"associatedVariants": "Associated variants", "associatedVariants": "Associated variants",
"manageLocations": "Manage locations", "manageLocations": "Manage locations",
"deleteWarning": "You are about to delete an inventory item. This action cannot be undone.", "deleteWarning": "You are about to delete an inventory item. This action cannot be undone.",
"editItemDetails": "Edit item details", "editItemDetails": "Edit item details",
"create": { "create": {
"title": "Add item", "title": "Add inventory item",
"details": "Details", "details": "Details",
"availability": "Availability", "availability": "Availability",
"locations": "Locations", "locations": "Locations",
@@ -514,7 +528,7 @@
}, },
"reservation": { "reservation": {
"header": "Reservation of {{itemName}}", "header": "Reservation of {{itemName}}",
"editItemDetails": "Edit item details", "editItemDetails": "Edit reservation",
"orderID": "Order ID", "orderID": "Order ID",
"description": "Description", "description": "Description",
"location": "Location", "location": "Location",
@@ -524,7 +538,7 @@
"reservedAmount": "Reserve amount", "reservedAmount": "Reserve amount",
"create": "Create reservation", "create": "Create reservation",
"itemToReserve": "Item to reserve", "itemToReserve": "Item to reserve",
"quantityPlaceholder": "How many do you want to reserve?", "quantityPlaceholder": "How much do you want to reserve?",
"descriptionPlaceholder": "What type of reservation is this?", "descriptionPlaceholder": "What type of reservation is this?",
"successToast": "Reservation was successfully created.", "successToast": "Reservation was successfully created.",
"updateSuccessToast": "Reservation was successfully updated.", "updateSuccessToast": "Reservation was successfully updated.",
@@ -554,16 +568,27 @@
}, },
"customers": { "customers": {
"domain": "Customers", "domain": "Customers",
"list": {
"noRecordsMessage": "Your customers will show up here."
},
"create": { "create": {
"header": "Create Customer", "header": "Create Customer",
"hint": "Create a new customer to manage their details.", "hint": "Create a new customer and manage their details.",
"successToast": "Customer {{email}} was successfully created." "successToast": "Customer {{email}} was successfully created."
}, },
"groups": { "groups": {
"label": "Customer groups", "label": "Customer groups",
"remove": "Are you sure you want to remove the customer from \"{{name}}\" customer group?", "remove": "Are you sure you want to remove the customer from \"{{name}}\" customer group?",
"removeMany": "Are you sure you want to customer from following customer groups: {{groups}}?", "removeMany": "Are you sure you want to customer from following customer groups: {{groups}}?",
"alreadyAddedTooltip": "The customer is already in this customer group." "alreadyAddedTooltip": "The customer is already in this customer group.",
"list": {
"noRecordsMessage": "This customer doesn't belong to any group."
},
"add": {
"list": {
"noRecordsMessage": "Please create a customer group first."
}
}
}, },
"edit": { "edit": {
"header": "Edit Customer", "header": "Edit Customer",
@@ -585,6 +610,7 @@
}, },
"customerGroups": { "customerGroups": {
"domain": "Customer Groups", "domain": "Customer Groups",
"subtitle": "Organize customers into groups. Groups can have different promotions and prices.",
"create": { "create": {
"header": "Create Customer Group", "header": "Create Customer Group",
"hint": "Create a new customer group to segment your customers.", "hint": "Create a new customer group to segment your customers.",
@@ -603,13 +629,19 @@
"alreadyAddedTooltip": "The customer has already been added to the group.", "alreadyAddedTooltip": "The customer has already been added to the group.",
"add": { "add": {
"successToast_one": "Customer was successfully added to the group.", "successToast_one": "Customer was successfully added to the group.",
"successToast_other": "Customers were successfully added to the group." "successToast_other": "Customers were successfully added to the group.",
"list": {
"noRecordsMessage": "Create a customer first."
}
}, },
"remove": { "remove": {
"title_one": "Remove customer", "title_one": "Remove customer",
"title_other": "Remove customers", "title_other": "Remove customers",
"description_one": "You are about to remove {{count}} customer from the customer group. This action cannot be undone.", "description_one": "You are about to remove {{count}} customer from the customer group. This action cannot be undone.",
"description_other": "You are about to remove {{count}} customers from the customer group. This action cannot be undone." "description_other": "You are about to remove {{count}} customers from the customer group. This action cannot be undone."
},
"list": {
"noRecordsMessage": "This group doesn't have customers."
} }
} }
}, },
@@ -617,6 +649,9 @@
"domain": "Orders", "domain": "Orders",
"cancelWarning": "You are about to cancel the order {{id}}. This action cannot be undone.", "cancelWarning": "You are about to cancel the order {{id}}. This action cannot be undone.",
"onDateFromSalesChannel": "{{date}} from {{salesChannel}}", "onDateFromSalesChannel": "{{date}} from {{salesChannel}}",
"list": {
"noRecordsMessage": "Your orders will show up here."
},
"summary": { "summary": {
"requestReturn": "Request return", "requestReturn": "Request return",
"allocateItems": "Allocate items", "allocateItems": "Allocate items",
@@ -927,13 +962,13 @@
}, },
"calculated": { "calculated": {
"label": "Calculated", "label": "Calculated",
"hint": "The shipping option's price is calculated by the fulfillment provider." "hint": "The shipping option's price is calculated by the fulfillment provider during checkout."
} }
} }
}, },
"enableInStore": { "enableInStore": {
"label": "Enable in store", "label": "Enable in store",
"hint": "Control the visibility of this option to customers in your store." "hint": "Whether customers can use this option during checkout."
}, },
"provider": "Fulfillment provider", "provider": "Fulfillment provider",
"profile": "Shipping profile" "profile": "Shipping profile"
@@ -962,13 +997,14 @@
"successToast": "Areas for {{name}} were successfully updated." "successToast": "Areas for {{name}} were successfully updated."
}, },
"fields": { "fields": {
"noRecords": "Currently not covered by any service zones.", "noRecords": "There are no service zones to add shipping options to.",
"tip": "A service zone is a collection of geographical zones or areas. It's used to restrict available shipping options to a defined set of locations." "tip": "A service zone is a collection of geographical zones or areas. It's used to restrict available shipping options to a defined set of locations."
} }
} }
}, },
"shippingProfile": { "shippingProfile": {
"domain": "Shipping Profiles", "domain": "Shipping Profiles",
"subtitle": "Group products with similar shipping requirements into profiles.",
"create": { "create": {
"header": "Create Shipping Profile", "header": "Create Shipping Profile",
"hint": "Create a new shipping profile to group products with similar shipping requirements.", "hint": "Create a new shipping profile to group products with similar shipping requirements.",
@@ -1076,19 +1112,20 @@
}, },
"edit": { "edit": {
"title": "Edit Tax Rate", "title": "Edit Tax Rate",
"description": "Edits tax rate for a tax region" "description": "Edits the tax rate of a tax region"
}, },
"create": { "create": {
"title": "Create Tax Rate Override", "title": "Create Tax Rate Override",
"description": "Creates tax rate overrides for a tax region" "description": "Create a tax rate that overrides the default tax rates for selected conditions."
} }
}, },
"taxRegions": { "taxRegions": {
"domain": "Tax Regions", "domain": "Tax Regions",
"subtitle": "Manage tax rates and settings for each region.",
"description": "Manage your region's tax structure", "description": "Manage your region's tax structure",
"create": { "create": {
"title": "Create Tax Region", "title": "Create Tax Region",
"description": "Creates a tax region with default tax rate" "description": "Creates a tax region with a default tax rate."
}, },
"create-child": { "create-child": {
"title": "Create Default Rate for Province", "title": "Create Default Rate for Province",
@@ -1102,7 +1139,7 @@
}, },
"is_combinable": { "is_combinable": {
"name": "Is combinable", "name": "Is combinable",
"hint": "If this tax rate can be combined with the default rate from province or parent" "hint": "Whether this tax rate can be combined with the default rate from province or parent tax region."
} }
} }
}, },
@@ -1112,12 +1149,11 @@
"details": "Promotion Details" "details": "Promotion Details"
}, },
"tabs": { "tabs": {
"template": "Template", "template": "Type",
"promotion": "Promotion", "details": "Details",
"campaign": "Campaign" "campaign": "Campaign"
}, },
"fields": { "fields": {
"method": "Method",
"type": "Type", "type": "Type",
"value_type": "Value Type", "value_type": "Value Type",
"value": "Value", "value": "Value",
@@ -1131,11 +1167,11 @@
"conditions": { "conditions": {
"rules": { "rules": {
"title": "Who can use this code?", "title": "Who can use this code?",
"description": "Is the customer allowed to add the promotion code? Discount code can be used by all customers if left untouched." "description": "Which customer is allowed to use the promotion code? Promotion code can be used by all customers if left untouched."
}, },
"target-rules": { "target-rules": {
"title": "What will the promotion be applied to?", "title": "What items will the promotion be applied to?",
"description": "The promotion will be applied to items that match the following conditions" "description": "The promotion will be applied to items that match the following conditions."
}, },
"buy-rules": { "buy-rules": {
"title": "What needs to be in the cart to unlock the promotion?", "title": "What needs to be in the cart to unlock the promotion?",
@@ -1144,7 +1180,7 @@
} }
}, },
"tooltips": { "tooltips": {
"campaignType": "Select the currency code in the promotion tab to enable it." "campaignType": "The currency code must be selected in the promotion to set a spend budget."
}, },
"errors": { "errors": {
"requiredField": "Required field", "requiredField": "Required field",
@@ -1157,20 +1193,20 @@
"edit": { "edit": {
"title": "Edit Promotion Details", "title": "Edit Promotion Details",
"rules": { "rules": {
"title": "Edit rules" "title": "Edit usage conditions"
}, },
"target-rules": { "target-rules": {
"title": "Edit target rules" "title": "Edit item conditions"
}, },
"buy-rules": { "buy-rules": {
"title": "Edit buy rules" "title": "Edit buy rules"
} }
}, },
"addToCampaign": { "addToCampaign": {
"title": "Add Promotion To Campaign" "title": "Promotion's Campaign"
}, },
"campaign_currency": { "campaign_currency": {
"tooltip": "Currency is carried over from the promotion. Change it on the promotions tab." "tooltip": "This is the promotion's currency. Change it from the Details tab."
}, },
"form": { "form": {
"required": "Required", "required": "Required",
@@ -1179,11 +1215,11 @@
"campaign": { "campaign": {
"existing": { "existing": {
"title": "Existing Campaign", "title": "Existing Campaign",
"description": "Would you like to add promotion to an existing campaign?" "description": "Add promotion to an existing campaign."
}, },
"new": { "new": {
"title": "New Campaign", "title": "New Campaign",
"description": "Would you like to create a new campaign with this promotion?" "description": "Create a new campaign for this promotion."
}, },
"none": { "none": {
"title": "Without Campaign", "title": "Without Campaign",
@@ -1196,16 +1232,16 @@
"method": { "method": {
"code": { "code": {
"title": "Promotion code", "title": "Promotion code",
"description": "Customers must enter this at checkout" "description": "Customers must enter this code at checkout"
}, },
"automatic": { "automatic": {
"title": "Automatic", "title": "Automatic",
"description": "Customers will see this at checkout" "description": "Customers will see this promotion at checkout"
} }
}, },
"max_quantity": { "max_quantity": {
"title": "Maximum Quantity", "title": "Maximum Quantity",
"description": "Maximum quantity of items this promotion applies to" "description": "Maximum quantity of items this promotion applies to."
}, },
"type": { "type": {
"standard": { "standard": {
@@ -1237,25 +1273,31 @@
"value_type": { "value_type": {
"fixed": { "fixed": {
"title": "Promotion Value", "title": "Promotion Value",
"description": "eg. 100" "description": "The amount to be discounted. eg. 100"
}, },
"percentage": { "percentage": {
"title": "Promotion Value", "title": "Promotion Value",
"description": "eg. 8%" "description": "The percentage to discount off the amount. eg. 8%"
} }
} }
}, },
"deleteWarning": "You are about to delete the promotion {{code}}. This action cannot be undone.", "deleteWarning": "You are about to delete the promotion {{code}}. This action cannot be undone.",
"createPromotionTitle": "Create Promotion", "createPromotionTitle": "Create Promotion",
"type": "Promotion type" "type": "Promotion type",
"conditions": {
"add": "Add condition",
"list": {
"noRecordsMessage": "Add a condition to restrict what items the promotion applies to."
}
}
}, },
"campaigns": { "campaigns": {
"domain": "Campaigns", "domain": "Campaigns",
"details": "Campaign details", "details": "Campaign details",
"status": { "status": {
"active": "active", "active": "Active",
"expired": "expired", "expired": "Expired",
"scheduled": "scheduled" "scheduled": "Scheduled"
}, },
"delete": { "delete": {
"title": "Are you sure?", "title": "Are you sure?",
@@ -1267,7 +1309,7 @@
"successToast": "Campaign '{{name}}' was successfully updated." "successToast": "Campaign '{{name}}' was successfully updated."
}, },
"create": { "create": {
"hint": "Create a promotional campaign", "hint": "Create a promotional campaign.",
"header": "Create Campaign", "header": "Create Campaign",
"successToast": "Campaign '{{name}}' was successfully created." "successToast": "Campaign '{{name}}' was successfully created."
}, },
@@ -1280,12 +1322,12 @@
"total_used": "Budget used", "total_used": "Budget used",
"budget_limit": "Budget limit", "budget_limit": "Budget limit",
"campaign_id": { "campaign_id": {
"hint": "A list of campaigns with the same currency code as the promotion" "hint": "Only campaigns with the same currency code as the promotion are shown in this list."
} }
}, },
"budget": { "budget": {
"create": { "create": {
"hint": "Create a budget for the campaign", "hint": "Create a budget for the campaign.",
"header": "Campaign Budget" "header": "Campaign Budget"
}, },
"details": "Campaign budget", "details": "Campaign budget",
@@ -1298,12 +1340,15 @@
"type": { "type": {
"spend": { "spend": {
"title": "Spend", "title": "Spend",
"description": "Limit usage based on a currency value" "description": "Set a limit on the total discounted amount of all promotion usages."
}, },
"usage": { "usage": {
"title": "Usage", "title": "Usage",
"description": "Limit usage based on how many times its used" "description": "Set a limit on how many times the promotion can be used."
} }
},
"edit": {
"header": "Edit Campaign Budget"
} }
}, },
"promotions": { "promotions": {
@@ -1316,6 +1361,14 @@
"currencyMismatch": "Currency of the promotion and campaign doesn't match", "currencyMismatch": "Currency of the promotion and campaign doesn't match",
"toast": { "toast": {
"success": "Successfully added {{count}} promotion(s) to campaign" "success": "Successfully added {{count}} promotion(s) to campaign"
},
"add": {
"list": {
"noRecordsMessage": "Create a promotion first."
}
},
"list": {
"noRecordsMessage": "There are no promotions in the campaign."
} }
}, },
"deleteCampaignWarning": "You are about to delete the campaign {{name}}. This action cannot be undone.", "deleteCampaignWarning": "You are about to delete the campaign {{name}}. This action cannot be undone.",
@@ -1323,6 +1376,7 @@
}, },
"priceLists": { "priceLists": {
"domain": "Price Lists", "domain": "Price Lists",
"subtitle": "Create sales or override prices for specific conditions.",
"delete": { "delete": {
"confirmation": "You are about to delete the price list {{title}}. This action cannot be undone.", "confirmation": "You are about to delete the price list {{title}}. This action cannot be undone.",
"successToast": "Price list {{title}} was successfully deleted." "successToast": "Price list {{title}} was successfully deleted."
@@ -1335,7 +1389,12 @@
"products": "Products", "products": "Products",
"prices": "Prices" "prices": "Prices"
}, },
"successToast": "Price list {{title}} was successfully created." "successToast": "Price list {{title}} was successfully created.",
"products": {
"list": {
"noRecordsMessage": "Create a product first."
}
}
}, },
"edit": { "edit": {
"header": "Edit Price List", "header": "Edit Price List",
@@ -1415,14 +1474,14 @@
}, },
"profile": { "profile": {
"domain": "Profile", "domain": "Profile",
"manageYourProfileDetails": "Manage your profile details", "manageYourProfileDetails": "Manage your profile details.",
"fields": { "fields": {
"languageLabel": "Language", "languageLabel": "Language",
"usageInsightsLabel": "Usage insights" "usageInsightsLabel": "Usage insights"
}, },
"edit": { "edit": {
"header": "Edit Profile", "header": "Edit Profile",
"languageHint": "The language you want to use in the admin dashboard. This will not change the language of your store.", "languageHint": "The language you want to use in the admin dashboard. This doesn't change the language of your store.",
"languagePlaceholder": "Select language", "languagePlaceholder": "Select language",
"usageInsightsHint": "Share usage insights and help us improve Medusa. You can read more about what we collect and how we use it in our <0>documentation</0>." "usageInsightsHint": "Share usage insights and help us improve Medusa. You can read more about what we collect and how we use it in our <0>documentation</0>."
}, },
@@ -1481,18 +1540,19 @@
}, },
"regions": { "regions": {
"domain": "Regions", "domain": "Regions",
"subtitle": "A region is an area that you sell products in. It can cover multipe countries, and has different tax rates, providers, and currency.",
"createRegion": "Create Region", "createRegion": "Create Region",
"createRegionHint": "Manage tax rates and providers for a set of countries.", "createRegionHint": "Manage tax rates and providers for a set of countries.",
"addCountries": "Add countries", "addCountries": "Add countries",
"editRegion": "Edit Region", "editRegion": "Edit Region",
"countriesHint": "Add the countries that should be included in this region.", "countriesHint": "Add the countries included in this region.",
"deleteRegionWarning": "You are about to delete the region {{name}}. This action cannot be undone.", "deleteRegionWarning": "You are about to delete the region {{name}}. This action cannot be undone.",
"removeCountriesWarning_one": "You are about to remove {{count}} country from the region. This action cannot be undone.", "removeCountriesWarning_one": "You are about to remove {{count}} country from the region. This action cannot be undone.",
"removeCountriesWarning_other": "You are about to remove {{count}} countries from the region. This action cannot be undone.", "removeCountriesWarning_other": "You are about to remove {{count}} countries from the region. This action cannot be undone.",
"removeCountryWarning": "You are about to remove the country {{name}} from the region. This action cannot be undone.", "removeCountryWarning": "You are about to remove the country {{name}} from the region. This action cannot be undone.",
"automaticTaxesHint": "When enabled taxes will only be calculated at checkout based on the shipping address.", "automaticTaxesHint": "When enabled, taxes will only be calculated at checkout based on the shipping address.",
"taxInclusiveHint": "When enabled prices in the region will be tax inclusive.", "taxInclusiveHint": "When enabled, prices in the region will be tax inclusive.",
"providersHint": " Add which payment providers should be available in this region.", "providersHint": " Add which payment providers are available in this region.",
"shippingOptions": "Shipping Options", "shippingOptions": "Shipping Options",
"deleteShippingOptionWarning": "You are about to delete the shipping option {{name}}. This action cannot be undone.", "deleteShippingOptionWarning": "You are about to delete the shipping option {{name}}. This action cannot be undone.",
"return": "Return", "return": "Return",
@@ -1500,6 +1560,9 @@
"priceType": "Price Type", "priceType": "Price Type",
"flatRate": "Flat Rate", "flatRate": "Flat Rate",
"calculated": "Calculated", "calculated": "Calculated",
"list": {
"noRecordsMessage": "Create a region for the areas that you sell in."
},
"toast": { "toast": {
"delete": "Region deleted successfully", "delete": "Region deleted successfully",
"edit": "Region edit saved", "edit": "Region edit saved",
@@ -1524,7 +1587,7 @@
}, },
"availability": { "availability": {
"adminOnly": "Admin only", "adminOnly": "Admin only",
"adminOnlyHint": "When enabled the shipping option will only be available in the admin dashboard, and not in the storefront." "adminOnlyHint": "When enabled, the shipping option will only be available in the admin dashboard, and not in the storefront."
}, },
"taxInclusiveHint": "When enabled, the shipping option's price will be tax inclusive.", "taxInclusiveHint": "When enabled, the shipping option's price will be tax inclusive.",
"requirements": { "requirements": {
@@ -1595,13 +1658,15 @@
}, },
"reservations": { "reservations": {
"domain": "Reservations", "domain": "Reservations",
"subtitle": "Manage the reserved quantity of inventory items.",
"deleteWarning": "You are about to delete a reservation. This action cannot be undone." "deleteWarning": "You are about to delete a reservation. This action cannot be undone."
}, },
"salesChannels": { "salesChannels": {
"domain": "Sales Channels", "domain": "Sales Channels",
"subtitle": "Manage the online and offline channels you sell products on.",
"createSalesChannel": "Create Sales Channel", "createSalesChannel": "Create Sales Channel",
"createSalesChannelHint": "Create a new sales channel to sell your products on.", "createSalesChannelHint": "Create a new sales channel to sell your products on.",
"enabledHint": "Specify if the sales channel is enabled or disabled.", "enabledHint": "Specify whether the sales channel is enabled.",
"removeProductsWarning_one": "You are about to remove {{count}} product from {{sales_channel}}.", "removeProductsWarning_one": "You are about to remove {{count}} product from {{sales_channel}}.",
"removeProductsWarning_other": "You are about to remove {{count}} products from {{sales_channel}}.", "removeProductsWarning_other": "You are about to remove {{count}} products from {{sales_channel}}.",
"addProducts": "Add Products", "addProducts": "Add Products",
@@ -1612,6 +1677,16 @@
"create": "Sales channel created successfully", "create": "Sales channel created successfully",
"update": "Sales channel updated successfully", "update": "Sales channel updated successfully",
"delete": "Sales channel deleted successfully" "delete": "Sales channel deleted successfully"
},
"products": {
"list": {
"noRecordsMessage": "There are no products in the sales channel."
},
"add": {
"list": {
"noRecordsMessage": "Create a product first."
}
}
} }
}, },
"apiKeyManagement": { "apiKeyManagement": {
@@ -1619,6 +1694,10 @@
"publishable": "Publishable API Keys", "publishable": "Publishable API Keys",
"secret": "Secret API Keys" "secret": "Secret API Keys"
}, },
"subtitle": {
"publishable": "Manage API keys used in the storefront to limit the scope of requests to specific sales channels.",
"secret": "Manage API keys used to authenticate admin users in admin applications."
},
"status": { "status": {
"active": "Active", "active": "Active",
"revoked": "Revoked" "revoked": "Revoked"
@@ -1631,7 +1710,7 @@
"createPublishableHeader": "Create Publishable API Key", "createPublishableHeader": "Create Publishable API Key",
"createPublishableHint": "Create a new publishable API key to limit the scope of requests to specific sales channels.", "createPublishableHint": "Create a new publishable API key to limit the scope of requests to specific sales channels.",
"createSecretHeader": "Create Secret API Key", "createSecretHeader": "Create Secret API Key",
"createSecretHint": "Create a new secret API key to access the Medusa API.", "createSecretHint": "Create a new secret API key to access the Medusa API as an authenticated admin user.",
"secretKeyCreatedHeader": "Secret Key Created", "secretKeyCreatedHeader": "Secret Key Created",
"secretKeyCreatedHint": "Your new secret key has been generated. Copy and securely store it now. This is the only time it will be displayed.", "secretKeyCreatedHint": "Your new secret key has been generated. Copy and securely store it now. This is the only time it will be displayed.",
"copySecretTokenSuccess": "Secret key was copied to clipboard.", "copySecretTokenSuccess": "Secret key was copied to clipboard.",
@@ -1645,7 +1724,10 @@
"salesChannels": { "salesChannels": {
"successToast_one": "{{count}} sales channel was successfully added to the API key.", "successToast_one": "{{count}} sales channel was successfully added to the API key.",
"successToast_other": "{{count}} sales channels were successfully added to the API key.", "successToast_other": "{{count}} sales channels were successfully added to the API key.",
"alreadyAddedTooltip": "The sales channel has already been added to the API key." "alreadyAddedTooltip": "The sales channel has already been added to the API key.",
"list": {
"noRecordsMessage": "There are no sales channels in the publishable API key's scope."
}
}, },
"delete": { "delete": {
"warning": "You are about to delete the API key {{title}}. This action cannot be undone.", "warning": "You are about to delete the API key {{title}}. This action cannot be undone.",
@@ -1655,6 +1737,11 @@
"warning": "You are about to revoke the API key {{title}}. This action cannot be undone.", "warning": "You are about to revoke the API key {{title}}. This action cannot be undone.",
"successToast": "API key {{title}} was successfully revoked." "successToast": "API key {{title}} was successfully revoked."
}, },
"addSalesChannels": {
"list": {
"noRecordsMessage": "Create a sales channel first."
}
},
"removeSalesChannel": { "removeSalesChannel": {
"warning": "You are about to remove the sales channel {{name}} from the API key. This action cannot be undone.", "warning": "You are about to remove the sales channel {{name}} from the API key. This action cannot be undone.",
"warningBatch_one": "You are about to remove {{count}} sales channel from the API key. This action cannot be undone.", "warningBatch_one": "You are about to remove {{count}} sales channel from the API key. This action cannot be undone.",
@@ -1727,11 +1814,15 @@
}, },
"workflowExecutions": { "workflowExecutions": {
"domain": "Workflows", "domain": "Workflows",
"subtitle": "View and keep track of workflow executions in your Medusa application.",
"transactionIdLabel": "Transaction ID", "transactionIdLabel": "Transaction ID",
"workflowIdLabel": "Workflow ID", "workflowIdLabel": "Workflow ID",
"progressLabel": "Progress", "progressLabel": "Progress",
"stepsCompletedLabel_one": "{{completed}} of {{count}} step", "stepsCompletedLabel_one": "{{completed}} of {{count}} step",
"stepsCompletedLabel_other": "{{completed}} of {{count}} steps", "stepsCompletedLabel_other": "{{completed}} of {{count}} steps",
"list": {
"noRecordsMessage": "No workflows have been executed, yet."
},
"history": { "history": {
"sectionTitle": "History", "sectionTitle": "History",
"runningState": "Running...", "runningState": "Running...",
@@ -1766,6 +1857,7 @@
}, },
"productTypes": { "productTypes": {
"domain": "Product Types", "domain": "Product Types",
"subtitle": "Organize your products into types.",
"create": { "create": {
"header": "Create Product Type", "header": "Create Product Type",
"hint": "Create a new product type to categorize your products.", "hint": "Create a new product type to categorize your products.",
@@ -1808,7 +1900,7 @@
"title": "Title", "title": "Title",
"customTitle": "Custom title", "customTitle": "Custom title",
"manageInventory": "Manage inventory", "manageInventory": "Manage inventory",
"inventoryKit": "Inventory kit", "inventoryKit": "Has inventory kit",
"inventoryItems": "Inventory items", "inventoryItems": "Inventory items",
"inventoryItem": "Inventory item", "inventoryItem": "Inventory item",
"requiredQuantity": "Required quantity", "requiredQuantity": "Required quantity",
@@ -140,6 +140,9 @@ export const ApiKeySalesChannelSection = ({
pageSize={PAGE_SIZE} pageSize={PAGE_SIZE}
pagination pagination
search search
noRecords={{
message: t("apiKeyManagement.salesChannels.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -1,4 +1,4 @@
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
@@ -52,11 +52,18 @@ export const ApiKeyManagementListTable = ({
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading level="h2"> <Heading level="h2">
{keyType === "publishable" {keyType === "publishable"
? t(`apiKeyManagement.domain.publishable`) ? t(`apiKeyManagement.domain.publishable`)
: t("apiKeyManagement.domain.secret")} : t("apiKeyManagement.domain.secret")}
</Heading> </Heading>
<Text className="text-ui-fg-subtle" size="small">
{keyType === "publishable"
? t(`apiKeyManagement.subtitle.publishable`)
: t("apiKeyManagement.subtitle.secret")}
</Text>
</div>
<Link to="create"> <Link to="create">
<Button variant="secondary" size="small"> <Button variant="secondary" size="small">
{t("actions.create")} {t("actions.create")}
@@ -156,6 +156,11 @@ export const ApiKeySalesChannelsForm = ({
queryObject={raw} queryObject={raw}
orderBy={["name", "created_at", "updated_at"]} orderBy={["name", "created_at", "updated_at"]}
layout="fill" layout="fill"
noRecords={{
message: t(
"apiKeyManagement.addSalesChannels.list.noRecordsMessage"
),
}}
/> />
</RouteFocusModal.Body> </RouteFocusModal.Body>
</form> </form>
@@ -11,10 +11,7 @@ import { useMemo, useState } from "react"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import * as zod from "zod" import * as zod from "zod"
import { import { RouteFocusModal, useRouteModal } from "../../../../components/modals"
RouteFocusModal,
useRouteModal,
} from "../../../../components/modals"
import { DataTable } from "../../../../components/table/data-table" import { DataTable } from "../../../../components/table/data-table"
import { useAddOrRemoveCampaignPromotions } from "../../../../hooks/api/campaigns" import { useAddOrRemoveCampaignPromotions } from "../../../../hooks/api/campaigns"
import { usePromotions } from "../../../../hooks/api/promotions" import { usePromotions } from "../../../../hooks/api/promotions"
@@ -151,6 +148,9 @@ export const AddCampaignPromotionsForm = ({
layout="fill" layout="fill"
pagination pagination
search search
noRecords={{
message: t("campaigns.promotions.add.list.noRecordsMessage"),
}}
/> />
</RouteFocusModal.Body> </RouteFocusModal.Body>
</form> </form>
@@ -18,7 +18,7 @@ export const CampaignBudgetEdit = () => {
return ( return (
<RouteDrawer> <RouteDrawer>
<RouteDrawer.Header> <RouteDrawer.Header>
<Heading>{t("campaigns.edit.header")}</Heading> <Heading>{t("campaigns.budget.edit.header")}</Heading>
</RouteDrawer.Header> </RouteDrawer.Header>
{!isLoading && campaign && <EditCampaignBudgetForm campaign={campaign} />} {!isLoading && campaign && <EditCampaignBudgetForm campaign={campaign} />}
@@ -115,6 +115,9 @@ export const CampaignPromotionSection = ({
shortcut: "r", shortcut: "r",
}, },
]} ]}
noRecords={{
message: t("campaigns.promotions.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -141,6 +141,9 @@ export const CategoryProductSection = ({
navigateTo={(row) => `/products/${row.id}`} navigateTo={(row) => `/products/${row.id}`}
isLoading={isLoading} isLoading={isLoading}
queryObject={raw} queryObject={raw}
noRecords={{
message: t("categories.products.list.noRecordsMessage"),
}}
/> />
<CommandBar open={!!Object.keys(selection).length}> <CommandBar open={!!Object.keys(selection).length}>
<CommandBar.Bar> <CommandBar.Bar>
@@ -1,6 +1,6 @@
import { PencilSquare, Trash } from "@medusajs/icons" import { PencilSquare, Trash } from "@medusajs/icons"
import { AdminProductCategoryResponse } from "@medusajs/types" import { AdminProductCategoryResponse } from "@medusajs/types"
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
@@ -64,7 +64,12 @@ export const CategoryListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("categories.domain")}</Heading> <Heading>{t("categories.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("categories.subtitle")}
</Text>
</div>
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">
<Button size="small" variant="secondary" asChild> <Button size="small" variant="secondary" asChild>
<Link to="organize">{t("categories.organize.action")}</Link> <Link to="organize">{t("categories.organize.action")}</Link>
@@ -129,6 +129,9 @@ export const CollectionProductSection = ({
shortcut: "r", shortcut: "r",
}, },
]} ]}
noRecords={{
message: t("collections.products.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -1,4 +1,4 @@
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
@@ -44,7 +44,12 @@ export const CollectionListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("collections.domain")}</Heading> <Heading>{t("collections.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("collections.subtitle")}
</Text>
</div>
<Link to="/collections/create"> <Link to="/collections/create">
<Button size="small" variant="secondary"> <Button size="small" variant="secondary">
{t("actions.create")} {t("actions.create")}
@@ -173,6 +173,9 @@ export const AddCustomersForm = ({
layout="fill" layout="fill"
search search
queryObject={raw} queryObject={raw}
noRecords={{
message: t("customerGroups.customers.add.list.noRecordsMessage"),
}}
/> />
</RouteFocusModal.Body> </RouteFocusModal.Body>
</form> </form>
@@ -126,6 +126,9 @@ export const CustomerGroupCustomerSection = ({
shortcut: "r", shortcut: "r",
}, },
]} ]}
noRecords={{
message: t("customerGroups.customers.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -1,5 +1,12 @@
import { PencilSquare, Trash } from "@medusajs/icons" import { PencilSquare, Trash } from "@medusajs/icons"
import { Button, Container, Heading, toast, usePrompt } from "@medusajs/ui" import {
Button,
Container,
Heading,
toast,
usePrompt,
Text,
} from "@medusajs/ui"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -50,7 +57,12 @@ export const CustomerGroupListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading level="h2">{t("customerGroups.domain")}</Heading> <Heading level="h2">{t("customerGroups.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("customerGroups.subtitle")}
</Text>
</div>
<Link to="/customer-groups/create"> <Link to="/customer-groups/create">
<Button size="small" variant="secondary"> <Button size="small" variant="secondary">
{t("actions.create")} {t("actions.create")}
@@ -149,6 +149,9 @@ export const CustomerGroupSection = ({
}, },
]} ]}
queryObject={raw} queryObject={raw}
noRecords={{
message: t("customers.groups.list.noRecordsMessage")
}}
/> />
</Container> </Container>
) )
@@ -74,6 +74,9 @@ export const CustomerListTable = () => {
navigateTo={(row) => row.original.id} navigateTo={(row) => row.original.id}
search search
queryObject={raw} queryObject={raw}
noRecords={{
message: t("customers.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -183,6 +183,9 @@ export const AddCustomerGroupsForm = ({
layout="fill" layout="fill"
search search
queryObject={raw} queryObject={raw}
noRecords={{
message: t("customers.groups.add.list.noRecordsMessage"),
}}
/> />
</RouteFocusModal.Body> </RouteFocusModal.Body>
</form> </form>
@@ -1,4 +1,4 @@
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { InventoryTypes } from "@medusajs/types" import { InventoryTypes } from "@medusajs/types"
import { DataTable } from "../../../../components/table/data-table" import { DataTable } from "../../../../components/table/data-table"
@@ -48,7 +48,12 @@ export const InventoryListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("inventory.domain")}</Heading> <Heading>{t("inventory.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("inventory.subtitle")}
</Text>
</div>
<Button size="small" variant="secondary" asChild> <Button size="small" variant="secondary" asChild>
<Link to="create">{t("actions.create")}</Link> <Link to="create">{t("actions.create")}</Link>
</Button> </Button>
@@ -61,6 +61,9 @@ export const OrderListTable = () => {
pageSize={PAGE_SIZE} pageSize={PAGE_SIZE}
orderBy={["display_id", "created_at", "updated_at"]} orderBy={["display_id", "created_at", "updated_at"]}
queryObject={raw} queryObject={raw}
noRecords={{
message: t("orders.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -17,6 +17,7 @@ import { useProductTableQuery } from "../../../../../hooks/table/query/use-produ
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { PriceListCreateProductsSchema } from "../../../common/schemas" import { PriceListCreateProductsSchema } from "../../../common/schemas"
import { PricingCreateSchemaType } from "./schema" import { PricingCreateSchemaType } from "./schema"
import { useTranslation } from "react-i18next"
type PriceListProductsFormProps = { type PriceListProductsFormProps = {
form: UseFormReturn<PricingCreateSchemaType> form: UseFormReturn<PricingCreateSchemaType>
@@ -33,6 +34,7 @@ function getInitialSelection(products: { id: string }[]) {
} }
export const PriceListProductsForm = ({ form }: PriceListProductsFormProps) => { export const PriceListProductsForm = ({ form }: PriceListProductsFormProps) => {
const { t } = useTranslation()
const { control, setValue } = form const { control, setValue } = form
const selectedIds = useWatch({ const selectedIds = useWatch({
@@ -128,6 +130,9 @@ export const PriceListProductsForm = ({ form }: PriceListProductsFormProps) => {
pagination pagination
search search
queryObject={raw} queryObject={raw}
noRecords={{
message: t("priceLists.create.products.list.noRecordsMessage"),
}}
/> />
</div> </div>
) )
@@ -1,4 +1,4 @@
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
@@ -43,7 +43,12 @@ export const PriceListListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("priceLists.domain")}</Heading> <Heading>{t("priceLists.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("priceLists.subtitle")}
</Text>
</div>
<Button size="small" variant="secondary" asChild> <Button size="small" variant="secondary" asChild>
<Link to="create">{t("actions.create")}</Link> <Link to="create">{t("actions.create")}</Link>
</Button> </Button>
@@ -1,4 +1,4 @@
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
@@ -42,7 +42,12 @@ export const ProductTypeListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("productTypes.domain")}</Heading> <Heading>{t("productTypes.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("productTypes.subtitle")}
</Text>
</div>
<Button size="small" variant="secondary" asChild> <Button size="small" variant="secondary" asChild>
<Link to="create">{t("actions.create")}</Link> <Link to="create">{t("actions.create")}</Link>
</Button> </Button>
@@ -319,7 +319,7 @@ export const CategoryCombobox = forwardRef<
{query ? ( {query ? (
<Trans <Trans
i18n={i18n} i18n={i18n}
i18nKey={"general.noSearchResultsFor"} i18nKey={"general.noResultsTitle"}
tOptions={{ tOptions={{
query: query, query: query,
}} }}
@@ -328,7 +328,7 @@ export const CategoryCombobox = forwardRef<
]} ]}
/> />
) : ( ) : (
t("general.noRecordsFound") t("general.noResultsTitle")
)} )}
</Text> </Text>
</div> </div>
@@ -10,10 +10,7 @@ import { Divider } from "../../../../../components/common/divider"
import { Form } from "../../../../../components/common/form" import { Form } from "../../../../../components/common/form"
import { Combobox } from "../../../../../components/inputs/combobox" import { Combobox } from "../../../../../components/inputs/combobox"
import { CountrySelect } from "../../../../../components/inputs/country-select" import { CountrySelect } from "../../../../../components/inputs/country-select"
import { import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
RouteDrawer,
useRouteModal,
} from "../../../../../components/modals"
import { useCreateProductVariant } from "../../../../../hooks/api/products" import { useCreateProductVariant } from "../../../../../hooks/api/products"
import { castNumber } from "../../../../../lib/cast-number" import { castNumber } from "../../../../../lib/cast-number"
import { optionalInt } from "../../../../../lib/validation" import { optionalInt } from "../../../../../lib/validation"
@@ -150,21 +147,6 @@ export const CreateProductVariantForm = ({
) )
}} }}
/> />
<Form.Field
control={form.control}
name="material"
render={({ field }) => {
return (
<Form.Item>
<Form.Label optional>{t("fields.material")}</Form.Label>
<Form.Control>
<Input {...field} />
</Form.Control>
<Form.ErrorMessage />
</Form.Item>
)
}}
/>
{product.options.map((option: any) => { {product.options.map((option: any) => {
return ( return (
<Form.Field <Form.Field
@@ -357,6 +339,21 @@ export const CreateProductVariantForm = ({
)} )}
<div className="flex flex-col gap-y-4"> <div className="flex flex-col gap-y-4">
<Heading level="h2">{t("products.attributes")}</Heading> <Heading level="h2">{t("products.attributes")}</Heading>
<Form.Field
control={form.control}
name="material"
render={({ field }) => {
return (
<Form.Item>
<Form.Label optional>{t("fields.material")}</Form.Label>
<Form.Control>
<Input {...field} />
</Form.Control>
<Form.ErrorMessage />
</Form.Item>
)
}}
/>
<Form.Field <Form.Field
control={form.control} control={form.control}
name="weight" name="weight"
@@ -75,6 +75,9 @@ export const ProductListTable = () => {
queryObject={raw} queryObject={raw}
navigateTo={(row) => `${row.original.id}`} navigateTo={(row) => `${row.original.id}`}
orderBy={["title", "created_at", "updated_at"]} orderBy={["title", "created_at", "updated_at"]}
noRecords={{
message: t("products.list.noRecordsMessage"),
}}
/> />
<Outlet /> <Outlet />
</Container> </Container>
@@ -6,10 +6,7 @@ import { useForm, useWatch } from "react-hook-form"
import { Trans, useTranslation } from "react-i18next" import { Trans, useTranslation } from "react-i18next"
import * as zod from "zod" import * as zod from "zod"
import { Form } from "../../../../../components/common/form" import { Form } from "../../../../../components/common/form"
import { import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
RouteDrawer,
useRouteModal,
} from "../../../../../components/modals"
import { useUpdatePromotion } from "../../../../../hooks/api/promotions" import { useUpdatePromotion } from "../../../../../hooks/api/promotions"
import { CreateCampaignFormFields } from "../../../../campaigns/common/components/create-campaign-form-fields" import { CreateCampaignFormFields } from "../../../../campaigns/common/components/create-campaign-form-fields"
import { CampaignDetails } from "./campaign-details" import { CampaignDetails } from "./campaign-details"
@@ -54,7 +51,7 @@ export const AddCampaignPromotionFields = ({
render={({ field }) => { render={({ field }) => {
return ( return (
<Form.Item> <Form.Item>
<Form.Label>Method</Form.Label> <Form.Label>{t("promotions.fields.campaign")}</Form.Label>
<Form.Control> <Form.Control>
<RadioGroup <RadioGroup
@@ -357,7 +357,7 @@ export const CreatePromotionForm = () => {
className="w-full" className="w-full"
value={Tab.PROMOTION} value={Tab.PROMOTION}
> >
{t("promotions.tabs.promotion")} {t("promotions.tabs.details")}
</ProgressTabs.Trigger> </ProgressTabs.Trigger>
<ProgressTabs.Trigger className="w-full" value={Tab.CAMPAIGN}> <ProgressTabs.Trigger className="w-full" value={Tab.CAMPAIGN}>
@@ -627,7 +627,7 @@ export const CreatePromotionForm = () => {
/> />
)} )}
<div className="flex gap-y-4 gap-x-2"> <div className="flex gap-x-2 gap-y-4">
{!currentTemplate?.hiddenFields?.includes( {!currentTemplate?.hiddenFields?.includes(
"application_method.value" "application_method.value"
) && ( ) && (
@@ -13,17 +13,17 @@ type RuleProps = {
function RuleBlock({ rule }: RuleProps) { function RuleBlock({ rule }: RuleProps) {
return ( return (
<div className="bg-ui-bg-subtle shadow-borders-base flex justify-around rounded-md p-2 align-center"> <div className="bg-ui-bg-subtle shadow-borders-base align-center flex justify-around rounded-md p-2">
<div className="flex text-ui-fg-subtle txt-compact-xsmall whitespace-nowrap items-center"> <div className="text-ui-fg-subtle txt-compact-xsmall flex items-center whitespace-nowrap">
<Badge <Badge
size="2xsmall" size="2xsmall"
key="rule-attribute" key="rule-attribute"
className="mx-1 txt-compact-xsmall-plus tag-neutral-text truncate inline-block" className="txt-compact-xsmall-plus tag-neutral-text mx-1 inline-block truncate"
> >
{rule.attribute_label} {rule.attribute_label}
</Badge> </Badge>
<span className="mx-1 txt-compact-2xsmall inline-block"> <span className="txt-compact-2xsmall mx-1 inline-block">
{rule.operator_label} {rule.operator_label}
</span> </span>
@@ -80,9 +80,12 @@ export const PromotionConditionsSection = ({
{!rules.length && ( {!rules.length && (
<NoRecords <NoRecords
className="h-[180px]" className="h-[180px]"
title="No records yet." title={t("general.noRecordsTitle")}
message="Please check back later or add a target condition today" message={t("promotions.conditions.list.noRecordsMessage")}
action={{ to: `${ruleType}/edit`, label: "Add condition" }} action={{
to: `${ruleType}/edit`,
label: t("promotions.conditions.add"),
}}
buttonVariant="transparentIconLeft" buttonVariant="transparentIconLeft"
/> />
)} )}
@@ -61,7 +61,7 @@ export const PromotionGeneralSection = ({
[PromotionStatus.EXPIRED]: ["red", t("statuses.expired")], [PromotionStatus.EXPIRED]: ["red", t("statuses.expired")],
}[getPromotionStatus(promotion)] as [ }[getPromotionStatus(promotion)] as [
"grey" | "orange" | "green" | "red", "grey" | "orange" | "green" | "red",
string, string
] ]
return ( return (
@@ -100,7 +100,7 @@ export const PromotionGeneralSection = ({
<div className="text-ui-fg-subtle grid grid-cols-2 items-start px-6 py-4"> <div className="text-ui-fg-subtle grid grid-cols-2 items-start px-6 py-4">
<Text size="small" weight="plus" leading="compact"> <Text size="small" weight="plus" leading="compact">
{t("promotions.fields.method")} {t("promotions.fields.campaign")}
</Text> </Text>
<Text size="small" leading="compact" className="text-pretty"> <Text size="small" leading="compact" className="text-pretty">
@@ -1,6 +1,13 @@
import { PencilSquare, Trash } from "@medusajs/icons" import { PencilSquare, Trash } from "@medusajs/icons"
import type { HttpTypes } from "@medusajs/types" import type { HttpTypes } from "@medusajs/types"
import { Button, Container, Heading, toast, usePrompt } from "@medusajs/ui" import {
Button,
Container,
Heading,
toast,
usePrompt,
Text,
} from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
@@ -56,7 +63,12 @@ export const RegionListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("regions.domain")}</Heading> <Heading>{t("regions.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("regions.subtitle")}
</Text>
</div>
<Link to="/settings/regions/create"> <Link to="/settings/regions/create">
<Button size="small" variant="secondary"> <Button size="small" variant="secondary">
{t("actions.create")} {t("actions.create")}
@@ -76,6 +88,9 @@ export const RegionListTable = () => {
pagination pagination
search search
queryObject={raw} queryObject={raw}
noRecords={{
message: t("regions.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -1,4 +1,4 @@
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { DataTable } from "../../../../../components/table/data-table" import { DataTable } from "../../../../../components/table/data-table"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
@@ -41,7 +41,12 @@ export const ReservationListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("reservations.domain")}</Heading> <Heading>{t("reservations.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("reservations.subtitle")}
</Text>
</div>
<Button variant="secondary" size="small" asChild> <Button variant="secondary" size="small" asChild>
<Link to="create">{t("actions.create")}</Link> <Link to="create">{t("actions.create")}</Link>
</Button> </Button>
@@ -11,10 +11,7 @@ import { useMemo, useState } from "react"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import * as zod from "zod" import * as zod from "zod"
import { import { RouteFocusModal, useRouteModal } from "../../../../components/modals"
RouteFocusModal,
useRouteModal,
} from "../../../../components/modals"
import { DataTable } from "../../../../components/table/data-table" import { DataTable } from "../../../../components/table/data-table"
import { useProducts } from "../../../../hooks/api/products" import { useProducts } from "../../../../hooks/api/products"
import { useSalesChannelAddProducts } from "../../../../hooks/api/sales-channels" import { useSalesChannelAddProducts } from "../../../../hooks/api/sales-channels"
@@ -168,6 +165,9 @@ export const AddProductsToSalesChannelForm = ({
layout="fill" layout="fill"
pagination pagination
search search
noRecords={{
message: t("salesChannels.products.add.list.noRecordsMessage"),
}}
/> />
</RouteFocusModal.Body> </RouteFocusModal.Body>
</form> </form>
@@ -149,6 +149,9 @@ export const SalesChannelProductSection = ({
isLoading={isLoading} isLoading={isLoading}
orderBy={["title", "variants", "status", "created_at", "updated_at"]} orderBy={["title", "variants", "status", "created_at", "updated_at"]}
queryObject={raw} queryObject={raw}
noRecords={{
message: t("salesChannels.products.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )
@@ -1,6 +1,13 @@
import { PencilSquare, Trash } from "@medusajs/icons" import { PencilSquare, Trash } from "@medusajs/icons"
import { SalesChannelDTO } from "@medusajs/types" import { SalesChannelDTO } from "@medusajs/types"
import { Button, Container, Heading, toast, usePrompt } from "@medusajs/ui" import {
Button,
Container,
Heading,
toast,
usePrompt,
Text,
} from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
@@ -52,7 +59,12 @@ export const SalesChannelListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading level="h2">{t("salesChannels.domain")}</Heading> <Heading level="h2">{t("salesChannels.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("salesChannels.subtitle")}
</Text>
</div>
<Link to="/settings/sales-channels/create"> <Link to="/settings/sales-channels/create">
<Button size="small" variant="secondary"> <Button size="small" variant="secondary">
{t("actions.create")} {t("actions.create")}
@@ -1,4 +1,4 @@
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
@@ -43,7 +43,12 @@ export const ShippingProfileListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("shippingProfile.domain")}</Heading> <Heading>{t("shippingProfile.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("shippingProfile.subtitle")}
</Text>
</div>
<div> <div>
<Button size="small" variant="secondary" asChild> <Button size="small" variant="secondary" asChild>
<Link to="create">{t("actions.create")}</Link> <Link to="create">{t("actions.create")}</Link>
@@ -1,6 +1,6 @@
import { Trash } from "@medusajs/icons" import { Trash } from "@medusajs/icons"
import { AdminTaxRegionResponse } from "@medusajs/types" import { AdminTaxRegionResponse } from "@medusajs/types"
import { Button, Container, Heading } from "@medusajs/ui" import { Button, Container, Heading, Text } from "@medusajs/ui"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { t } from "i18next" import { t } from "i18next"
import { useMemo } from "react" import { useMemo } from "react"
@@ -47,7 +47,12 @@ export const TaxRegionListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading level="h2">{t("taxes.domain")}</Heading> <Heading level="h2">{t("taxes.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t("taxRegions.subtitle")}
</Text>
</div>
<Button size="small" variant="secondary" asChild> <Button size="small" variant="secondary" asChild>
<Link to="/settings/taxes/create">{t("actions.create")}</Link> <Link to="/settings/taxes/create">{t("actions.create")}</Link>
</Button> </Button>
@@ -1,4 +1,4 @@
import { Container, Heading } from "@medusajs/ui" import { Container, Heading, Text } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { DataTable } from "../../../../../components/table/data-table" import { DataTable } from "../../../../../components/table/data-table"
@@ -55,7 +55,12 @@ export const WorkflowExecutionListTable = () => {
return ( return (
<Container className="divide-y p-0"> <Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4"> <div className="flex items-center justify-between px-6 py-4">
<div>
<Heading>{t("workflowExecutions.domain")}</Heading> <Heading>{t("workflowExecutions.domain")}</Heading>
<Text className="text-ui-fg-subtle" size="small">
{t(`workflowExecutions.subtitle`)}
</Text>
</div>
</div> </div>
<DataTable <DataTable
table={table} table={table}
@@ -67,6 +72,9 @@ export const WorkflowExecutionListTable = () => {
search search
pagination pagination
queryObject={raw} queryObject={raw}
noRecords={{
message: t("workflowExecutions.list.noRecordsMessage"),
}}
/> />
</Container> </Container>
) )