feat(admin-sdk,admin-bundler,admin-shared,medusa): Restructure admin packages (#8988)
**What** - Renames /admin-next -> /admin - Renames @medusajs/admin-sdk -> @medusajs/admin-bundler - Creates a new package called @medusajs/admin-sdk that will hold all tooling relevant to creating admin extensions. This is currently `defineRouteConfig` and `defineWidgetConfig`, but will eventually also export methods for adding custom fields, register translation, etc. - cc: @shahednasser we should update the examples in the docs so these functions are imported from `@medusajs/admin-sdk`. People will also need to install the package in their project, as it's no longer a transient dependency. - cc: @olivermrbl we might want to publish a changelog when this is merged, as it is a breaking change, and will require people to import the `defineXConfig` from the new package instead of `@medusajs/admin-shared`. - Updates CODEOWNERS so /admin packages does not require a review from the UI team.
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
|
||||
import { countries, getCountryByIso2 } from "./data/countries"
|
||||
|
||||
export const isSameAddress = (
|
||||
a?: HttpTypes.AdminOrderAddress | null,
|
||||
b?: HttpTypes.AdminOrderAddress | null
|
||||
) => {
|
||||
if (!a || !b) {
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
a.first_name === b.first_name &&
|
||||
a.last_name === b.last_name &&
|
||||
a.address_1 === b.address_1 &&
|
||||
a.address_2 === b.address_2 &&
|
||||
a.city === b.city &&
|
||||
a.postal_code === b.postal_code &&
|
||||
a.province === b.province &&
|
||||
a.country_code === b.country_code
|
||||
)
|
||||
}
|
||||
|
||||
export const getFormattedAddress = ({
|
||||
address,
|
||||
}: {
|
||||
address?: HttpTypes.AdminOrderAddress | null
|
||||
}) => {
|
||||
if (!address) {
|
||||
return []
|
||||
}
|
||||
|
||||
const {
|
||||
first_name,
|
||||
last_name,
|
||||
company,
|
||||
address_1,
|
||||
address_2,
|
||||
city,
|
||||
postal_code,
|
||||
province,
|
||||
country,
|
||||
country_code,
|
||||
} = address
|
||||
|
||||
const name = [first_name, last_name].filter(Boolean).join(" ")
|
||||
|
||||
const formattedAddress: string[] = []
|
||||
|
||||
if (name) {
|
||||
formattedAddress.push(name)
|
||||
}
|
||||
|
||||
if (company) {
|
||||
formattedAddress.push(company)
|
||||
}
|
||||
|
||||
if (address_1) {
|
||||
formattedAddress.push(address_1)
|
||||
}
|
||||
|
||||
if (address_2) {
|
||||
formattedAddress.push(address_2)
|
||||
}
|
||||
|
||||
const cityProvincePostal = [city, province, postal_code]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
|
||||
if (cityProvincePostal) {
|
||||
formattedAddress.push(cityProvincePostal)
|
||||
}
|
||||
|
||||
if (country) {
|
||||
formattedAddress.push(country.display_name!)
|
||||
} else if (country_code) {
|
||||
const country = getCountryByIso2(country_code)
|
||||
|
||||
if (country) {
|
||||
formattedAddress.push(country.display_name)
|
||||
} else {
|
||||
formattedAddress.push(country_code.toUpperCase())
|
||||
}
|
||||
}
|
||||
|
||||
return formattedAddress
|
||||
}
|
||||
|
||||
export const getFormattedCountry = (countryCode: string | null | undefined) => {
|
||||
if (!countryCode) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const country = countries.find((c) => c.iso_2 === countryCode)
|
||||
return country ? country.display_name : countryCode
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Helper function to cast a z.union([z.number(), z.string()]) to a number
|
||||
*/
|
||||
export const castNumber = (number: number | string) => {
|
||||
return typeof number === "string" ? Number(number.replace(",", ".")) : number
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import Medusa from "@medusajs/js-sdk"
|
||||
|
||||
export const backendUrl = __BACKEND_URL__ ?? "http://localhost:9000"
|
||||
|
||||
export const sdk = new Medusa({
|
||||
baseUrl: backendUrl,
|
||||
auth: {
|
||||
type: "session",
|
||||
},
|
||||
})
|
||||
|
||||
// useful when you want to call the BE from the console and try things out quickly
|
||||
if (typeof window !== "undefined") {
|
||||
;(window as any).__sdk = sdk
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./client"
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Pick properties from an object and copy them to a new object
|
||||
* @param obj
|
||||
* @param keys
|
||||
*/
|
||||
export function pick(obj: Record<string, any>, keys: string[]) {
|
||||
const ret: Record<string, any> = {}
|
||||
|
||||
keys.forEach((k) => {
|
||||
if (k in obj) {
|
||||
ret[k] = obj[k]
|
||||
}
|
||||
})
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove properties that are `null` or `undefined` from the object.
|
||||
* @param obj
|
||||
*/
|
||||
export function cleanNonValues(obj: Record<string, any>) {
|
||||
const ret: Record<string, any> = {}
|
||||
|
||||
for (const key in obj) {
|
||||
if (obj[key] !== null && typeof obj[key] !== "undefined") {
|
||||
ret[key] = obj[key]
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,734 @@
|
||||
/** This file is auto-generated. Do not modify it manually. */
|
||||
export type CurrencyInfo = {
|
||||
code: string
|
||||
name: string
|
||||
symbol_native: string
|
||||
decimal_digits: number
|
||||
}
|
||||
|
||||
export const currencies: Record<string, CurrencyInfo> = {
|
||||
USD: {
|
||||
code: "USD",
|
||||
name: "US Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
CAD: {
|
||||
code: "CAD",
|
||||
name: "Canadian Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
EUR: {
|
||||
code: "EUR",
|
||||
name: "Euro",
|
||||
symbol_native: "€",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
AED: {
|
||||
code: "AED",
|
||||
name: "United Arab Emirates Dirham",
|
||||
symbol_native: "د.إ.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
AFN: {
|
||||
code: "AFN",
|
||||
name: "Afghan Afghani",
|
||||
symbol_native: "؋",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
ALL: {
|
||||
code: "ALL",
|
||||
name: "Albanian Lek",
|
||||
symbol_native: "Lek",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
AMD: {
|
||||
code: "AMD",
|
||||
name: "Armenian Dram",
|
||||
symbol_native: "դր.",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
ARS: {
|
||||
code: "ARS",
|
||||
name: "Argentine Peso",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
AUD: {
|
||||
code: "AUD",
|
||||
name: "Australian Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
AZN: {
|
||||
code: "AZN",
|
||||
name: "Azerbaijani Manat",
|
||||
symbol_native: "ман.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BAM: {
|
||||
code: "BAM",
|
||||
name: "Bosnia-Herzegovina Convertible Mark",
|
||||
symbol_native: "KM",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BDT: {
|
||||
code: "BDT",
|
||||
name: "Bangladeshi Taka",
|
||||
symbol_native: "৳",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BGN: {
|
||||
code: "BGN",
|
||||
name: "Bulgarian Lev",
|
||||
symbol_native: "лв.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BHD: {
|
||||
code: "BHD",
|
||||
name: "Bahraini Dinar",
|
||||
symbol_native: "د.ب.",
|
||||
decimal_digits: 3,
|
||||
},
|
||||
BIF: {
|
||||
code: "BIF",
|
||||
name: "Burundian Franc",
|
||||
symbol_native: "FBu",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
BND: {
|
||||
code: "BND",
|
||||
name: "Brunei Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BOB: {
|
||||
code: "BOB",
|
||||
name: "Bolivian Boliviano",
|
||||
symbol_native: "Bs",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BRL: {
|
||||
code: "BRL",
|
||||
name: "Brazilian Real",
|
||||
symbol_native: "R$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BWP: {
|
||||
code: "BWP",
|
||||
name: "Botswanan Pula",
|
||||
symbol_native: "P",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BYN: {
|
||||
code: "BYN",
|
||||
name: "Belarusian Ruble",
|
||||
symbol_native: "руб.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
BZD: {
|
||||
code: "BZD",
|
||||
name: "Belize Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
CDF: {
|
||||
code: "CDF",
|
||||
name: "Congolese Franc",
|
||||
symbol_native: "FrCD",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
CHF: {
|
||||
code: "CHF",
|
||||
name: "Swiss Franc",
|
||||
symbol_native: "CHF",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
CLP: {
|
||||
code: "CLP",
|
||||
name: "Chilean Peso",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
CNY: {
|
||||
code: "CNY",
|
||||
name: "Chinese Yuan",
|
||||
symbol_native: "CN¥",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
COP: {
|
||||
code: "COP",
|
||||
name: "Colombian Peso",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
CRC: {
|
||||
code: "CRC",
|
||||
name: "Costa Rican Colón",
|
||||
symbol_native: "₡",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
CVE: {
|
||||
code: "CVE",
|
||||
name: "Cape Verdean Escudo",
|
||||
symbol_native: "CV$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
CZK: {
|
||||
code: "CZK",
|
||||
name: "Czech Republic Koruna",
|
||||
symbol_native: "Kč",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
DJF: {
|
||||
code: "DJF",
|
||||
name: "Djiboutian Franc",
|
||||
symbol_native: "Fdj",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
DKK: {
|
||||
code: "DKK",
|
||||
name: "Danish Krone",
|
||||
symbol_native: "kr",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
DOP: {
|
||||
code: "DOP",
|
||||
name: "Dominican Peso",
|
||||
symbol_native: "RD$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
DZD: {
|
||||
code: "DZD",
|
||||
name: "Algerian Dinar",
|
||||
symbol_native: "د.ج.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
EEK: {
|
||||
code: "EEK",
|
||||
name: "Estonian Kroon",
|
||||
symbol_native: "kr",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
EGP: {
|
||||
code: "EGP",
|
||||
name: "Egyptian Pound",
|
||||
symbol_native: "ج.م.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
ERN: {
|
||||
code: "ERN",
|
||||
name: "Eritrean Nakfa",
|
||||
symbol_native: "Nfk",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
ETB: {
|
||||
code: "ETB",
|
||||
name: "Ethiopian Birr",
|
||||
symbol_native: "Br",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
GBP: {
|
||||
code: "GBP",
|
||||
name: "British Pound Sterling",
|
||||
symbol_native: "£",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
GEL: {
|
||||
code: "GEL",
|
||||
name: "Georgian Lari",
|
||||
symbol_native: "GEL",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
GHS: {
|
||||
code: "GHS",
|
||||
name: "Ghanaian Cedi",
|
||||
symbol_native: "GH₵",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
GNF: {
|
||||
code: "GNF",
|
||||
name: "Guinean Franc",
|
||||
symbol_native: "FG",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
GTQ: {
|
||||
code: "GTQ",
|
||||
name: "Guatemalan Quetzal",
|
||||
symbol_native: "Q",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
HKD: {
|
||||
code: "HKD",
|
||||
name: "Hong Kong Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
HNL: {
|
||||
code: "HNL",
|
||||
name: "Honduran Lempira",
|
||||
symbol_native: "L",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
HRK: {
|
||||
code: "HRK",
|
||||
name: "Croatian Kuna",
|
||||
symbol_native: "kn",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
HUF: {
|
||||
code: "HUF",
|
||||
name: "Hungarian Forint",
|
||||
symbol_native: "Ft",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
IDR: {
|
||||
code: "IDR",
|
||||
name: "Indonesian Rupiah",
|
||||
symbol_native: "Rp",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
ILS: {
|
||||
code: "ILS",
|
||||
name: "Israeli New Sheqel",
|
||||
symbol_native: "₪",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
INR: {
|
||||
code: "INR",
|
||||
name: "Indian Rupee",
|
||||
symbol_native: "₹",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
IQD: {
|
||||
code: "IQD",
|
||||
name: "Iraqi Dinar",
|
||||
symbol_native: "د.ع.",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
IRR: {
|
||||
code: "IRR",
|
||||
name: "Iranian Rial",
|
||||
symbol_native: "﷼",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
ISK: {
|
||||
code: "ISK",
|
||||
name: "Icelandic Króna",
|
||||
symbol_native: "kr",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
JMD: {
|
||||
code: "JMD",
|
||||
name: "Jamaican Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
JOD: {
|
||||
code: "JOD",
|
||||
name: "Jordanian Dinar",
|
||||
symbol_native: "د.أ.",
|
||||
decimal_digits: 3,
|
||||
},
|
||||
JPY: {
|
||||
code: "JPY",
|
||||
name: "Japanese Yen",
|
||||
symbol_native: "¥",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
KES: {
|
||||
code: "KES",
|
||||
name: "Kenyan Shilling",
|
||||
symbol_native: "Ksh",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
KHR: {
|
||||
code: "KHR",
|
||||
name: "Cambodian Riel",
|
||||
symbol_native: "៛",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
KMF: {
|
||||
code: "KMF",
|
||||
name: "Comorian Franc",
|
||||
symbol_native: "FC",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
KRW: {
|
||||
code: "KRW",
|
||||
name: "South Korean Won",
|
||||
symbol_native: "₩",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
KWD: {
|
||||
code: "KWD",
|
||||
name: "Kuwaiti Dinar",
|
||||
symbol_native: "د.ك.",
|
||||
decimal_digits: 3,
|
||||
},
|
||||
KZT: {
|
||||
code: "KZT",
|
||||
name: "Kazakhstani Tenge",
|
||||
symbol_native: "тңг.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
LBP: {
|
||||
code: "LBP",
|
||||
name: "Lebanese Pound",
|
||||
symbol_native: "ل.ل.",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
LKR: {
|
||||
code: "LKR",
|
||||
name: "Sri Lankan Rupee",
|
||||
symbol_native: "SL Re",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
LTL: {
|
||||
code: "LTL",
|
||||
name: "Lithuanian Litas",
|
||||
symbol_native: "Lt",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
LVL: {
|
||||
code: "LVL",
|
||||
name: "Latvian Lats",
|
||||
symbol_native: "Ls",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
LYD: {
|
||||
code: "LYD",
|
||||
name: "Libyan Dinar",
|
||||
symbol_native: "د.ل.",
|
||||
decimal_digits: 3,
|
||||
},
|
||||
MAD: {
|
||||
code: "MAD",
|
||||
name: "Moroccan Dirham",
|
||||
symbol_native: "د.م.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
MDL: {
|
||||
code: "MDL",
|
||||
name: "Moldovan Leu",
|
||||
symbol_native: "MDL",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
MGA: {
|
||||
code: "MGA",
|
||||
name: "Malagasy Ariary",
|
||||
symbol_native: "MGA",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
MKD: {
|
||||
code: "MKD",
|
||||
name: "Macedonian Denar",
|
||||
symbol_native: "MKD",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
MMK: {
|
||||
code: "MMK",
|
||||
name: "Myanma Kyat",
|
||||
symbol_native: "K",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
MNT: {
|
||||
code: "MNT",
|
||||
name: "Mongolian Tugrig",
|
||||
symbol_native: "₮",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
MOP: {
|
||||
code: "MOP",
|
||||
name: "Macanese Pataca",
|
||||
symbol_native: "MOP$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
MUR: {
|
||||
code: "MUR",
|
||||
name: "Mauritian Rupee",
|
||||
symbol_native: "MURs",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
MXN: {
|
||||
code: "MXN",
|
||||
name: "Mexican Peso",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
MYR: {
|
||||
code: "MYR",
|
||||
name: "Malaysian Ringgit",
|
||||
symbol_native: "RM",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
MZN: {
|
||||
code: "MZN",
|
||||
name: "Mozambican Metical",
|
||||
symbol_native: "MTn",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
NAD: {
|
||||
code: "NAD",
|
||||
name: "Namibian Dollar",
|
||||
symbol_native: "N$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
NGN: {
|
||||
code: "NGN",
|
||||
name: "Nigerian Naira",
|
||||
symbol_native: "₦",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
NIO: {
|
||||
code: "NIO",
|
||||
name: "Nicaraguan Córdoba",
|
||||
symbol_native: "C$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
NOK: {
|
||||
code: "NOK",
|
||||
name: "Norwegian Krone",
|
||||
symbol_native: "kr",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
NPR: {
|
||||
code: "NPR",
|
||||
name: "Nepalese Rupee",
|
||||
symbol_native: "नेरू",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
NZD: {
|
||||
code: "NZD",
|
||||
name: "New Zealand Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
OMR: {
|
||||
code: "OMR",
|
||||
name: "Omani Rial",
|
||||
symbol_native: "ر.ع.",
|
||||
decimal_digits: 3,
|
||||
},
|
||||
PAB: {
|
||||
code: "PAB",
|
||||
name: "Panamanian Balboa",
|
||||
symbol_native: "B/.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
PEN: {
|
||||
code: "PEN",
|
||||
name: "Peruvian Nuevo Sol",
|
||||
symbol_native: "S/.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
PHP: {
|
||||
code: "PHP",
|
||||
name: "Philippine Peso",
|
||||
symbol_native: "₱",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
PKR: {
|
||||
code: "PKR",
|
||||
name: "Pakistani Rupee",
|
||||
symbol_native: "₨",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
PLN: {
|
||||
code: "PLN",
|
||||
name: "Polish Zloty",
|
||||
symbol_native: "zł",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
PYG: {
|
||||
code: "PYG",
|
||||
name: "Paraguayan Guarani",
|
||||
symbol_native: "₲",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
QAR: {
|
||||
code: "QAR",
|
||||
name: "Qatari Rial",
|
||||
symbol_native: "ر.ق.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
RON: {
|
||||
code: "RON",
|
||||
name: "Romanian Leu",
|
||||
symbol_native: "RON",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
RSD: {
|
||||
code: "RSD",
|
||||
name: "Serbian Dinar",
|
||||
symbol_native: "дин.",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
RUB: {
|
||||
code: "RUB",
|
||||
name: "Russian Ruble",
|
||||
symbol_native: "₽.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
RWF: {
|
||||
code: "RWF",
|
||||
name: "Rwandan Franc",
|
||||
symbol_native: "FR",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
SAR: {
|
||||
code: "SAR",
|
||||
name: "Saudi Riyal",
|
||||
symbol_native: "ر.س.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
SDG: {
|
||||
code: "SDG",
|
||||
name: "Sudanese Pound",
|
||||
symbol_native: "SDG",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
SEK: {
|
||||
code: "SEK",
|
||||
name: "Swedish Krona",
|
||||
symbol_native: "kr",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
SGD: {
|
||||
code: "SGD",
|
||||
name: "Singapore Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
SOS: {
|
||||
code: "SOS",
|
||||
name: "Somali Shilling",
|
||||
symbol_native: "Ssh",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
SYP: {
|
||||
code: "SYP",
|
||||
name: "Syrian Pound",
|
||||
symbol_native: "ل.س.",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
THB: {
|
||||
code: "THB",
|
||||
name: "Thai Baht",
|
||||
symbol_native: "฿",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
TND: {
|
||||
code: "TND",
|
||||
name: "Tunisian Dinar",
|
||||
symbol_native: "د.ت.",
|
||||
decimal_digits: 3,
|
||||
},
|
||||
TOP: {
|
||||
code: "TOP",
|
||||
name: "Tongan Paʻanga",
|
||||
symbol_native: "T$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
TRY: {
|
||||
code: "TRY",
|
||||
name: "Turkish Lira",
|
||||
symbol_native: "TL",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
TTD: {
|
||||
code: "TTD",
|
||||
name: "Trinidad and Tobago Dollar",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
TWD: {
|
||||
code: "TWD",
|
||||
name: "New Taiwan Dollar",
|
||||
symbol_native: "NT$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
TZS: {
|
||||
code: "TZS",
|
||||
name: "Tanzanian Shilling",
|
||||
symbol_native: "TSh",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
UAH: {
|
||||
code: "UAH",
|
||||
name: "Ukrainian Hryvnia",
|
||||
symbol_native: "₴",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
UGX: {
|
||||
code: "UGX",
|
||||
name: "Ugandan Shilling",
|
||||
symbol_native: "USh",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
UYU: {
|
||||
code: "UYU",
|
||||
name: "Uruguayan Peso",
|
||||
symbol_native: "$",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
UZS: {
|
||||
code: "UZS",
|
||||
name: "Uzbekistan Som",
|
||||
symbol_native: "UZS",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
VEF: {
|
||||
code: "VEF",
|
||||
name: "Venezuelan Bolívar",
|
||||
symbol_native: "Bs.F.",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
VND: {
|
||||
code: "VND",
|
||||
name: "Vietnamese Dong",
|
||||
symbol_native: "₫",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
XAF: {
|
||||
code: "XAF",
|
||||
name: "CFA Franc BEAC",
|
||||
symbol_native: "FCFA",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
XOF: {
|
||||
code: "XOF",
|
||||
name: "CFA Franc BCEAO",
|
||||
symbol_native: "CFA",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
YER: {
|
||||
code: "YER",
|
||||
name: "Yemeni Rial",
|
||||
symbol_native: "ر.ي.",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
ZAR: {
|
||||
code: "ZAR",
|
||||
name: "South African Rand",
|
||||
symbol_native: "R",
|
||||
decimal_digits: 2,
|
||||
},
|
||||
ZMK: {
|
||||
code: "ZMK",
|
||||
name: "Zambian Kwacha",
|
||||
symbol_native: "ZK",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
ZWL: {
|
||||
code: "ZWL",
|
||||
name: "Zimbabwean Dollar",
|
||||
symbol_native: "ZWL$",
|
||||
decimal_digits: 0,
|
||||
},
|
||||
}
|
||||
|
||||
export function getCurrencySymbol(code: string) {
|
||||
return currencies[code.toUpperCase()].symbol_native
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { RouteObject } from "react-router-dom"
|
||||
import { ErrorBoundary } from "../components/utilities/error-boundary"
|
||||
|
||||
/**
|
||||
* Used to test if a route is a settings route.
|
||||
*/
|
||||
export const settingsRouteRegex = /^\/settings\//
|
||||
|
||||
export const createRouteMap = (
|
||||
routes: { path: string; Component: () => JSX.Element }[],
|
||||
ignore?: string
|
||||
): RouteObject[] => {
|
||||
const root: RouteObject[] = []
|
||||
|
||||
const addRoute = (
|
||||
pathSegments: string[],
|
||||
Component: () => JSX.Element,
|
||||
currentLevel: RouteObject[]
|
||||
) => {
|
||||
if (!pathSegments.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const [currentSegment, ...remainingSegments] = pathSegments
|
||||
let route = currentLevel.find((r) => r.path === currentSegment)
|
||||
|
||||
if (!route) {
|
||||
route = { path: currentSegment, children: [] }
|
||||
currentLevel.push(route)
|
||||
}
|
||||
|
||||
if (remainingSegments.length === 0) {
|
||||
route.children ||= []
|
||||
route.children.push({
|
||||
path: "",
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
async lazy() {
|
||||
return { Component }
|
||||
},
|
||||
})
|
||||
} else {
|
||||
route.children ||= []
|
||||
addRoute(remainingSegments, Component, route.children)
|
||||
}
|
||||
}
|
||||
|
||||
routes.forEach(({ path, Component }) => {
|
||||
// Remove the ignore segment from the path if it is provided
|
||||
const cleanedPath = ignore
|
||||
? path.replace(ignore, "").replace(/^\/+/, "")
|
||||
: path.replace(/^\/+/, "")
|
||||
const pathSegments = cleanedPath.split("/").filter(Boolean)
|
||||
addRoute(pathSegments, Component, root)
|
||||
})
|
||||
|
||||
return root
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { castNumber } from "./cast-number"
|
||||
|
||||
export function transformNullableFormValue<T>(
|
||||
value: T,
|
||||
nullify = true
|
||||
): T | undefined | null {
|
||||
if (typeof value === "string" && value.trim() === "") {
|
||||
return nullify ? null : undefined
|
||||
}
|
||||
|
||||
if (Array.isArray(value) && value.length === 0) {
|
||||
return nullify ? null : undefined
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
type Nullable<T> = { [K in keyof T]: T[K] | null }
|
||||
type Optional<T> = { [K in keyof T]: T[K] | undefined }
|
||||
|
||||
export function transformNullableFormData<
|
||||
T extends Record<string, unknown>,
|
||||
K extends boolean = true
|
||||
>(data: T, nullify: K = true as K): K extends true ? Nullable<T> : Optional<T> {
|
||||
return Object.entries(data).reduce((acc, [key, value]) => {
|
||||
return {
|
||||
...acc,
|
||||
[key]: transformNullableFormValue(value, nullify),
|
||||
}
|
||||
}, {} as K extends true ? Nullable<T> : Optional<T>)
|
||||
}
|
||||
|
||||
export function transformNullableFormNumber<K extends boolean = true>(
|
||||
value?: string | number,
|
||||
nullify: K = true as K
|
||||
): K extends true ? number | null : number | undefined {
|
||||
if (
|
||||
typeof value === "undefined" ||
|
||||
(typeof value === "string" && value.trim() === "")
|
||||
) {
|
||||
return (nullify ? null : undefined) as K extends true
|
||||
? number | null
|
||||
: number | undefined
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
return castNumber(value)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
type NullableNumbers = Record<string, number | null>
|
||||
type OptionalNumbers = Record<string, number | undefined>
|
||||
|
||||
export function transformNullableFormNumbers<
|
||||
T extends Record<string, string | number | undefined>,
|
||||
K extends boolean = true
|
||||
>(
|
||||
data: T,
|
||||
nullify: K = true as K
|
||||
): K extends true ? NullableNumbers : OptionalNumbers {
|
||||
return Object.entries(data).reduce((acc, [key, value]) => {
|
||||
return {
|
||||
...acc,
|
||||
[key]: transformNullableFormNumber(value, nullify),
|
||||
}
|
||||
}, {} as K extends true ? NullableNumbers : OptionalNumbers)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export const formatCurrency = (amount: number, currency: string) => {
|
||||
return new Intl.NumberFormat("en-US", {
|
||||
style: "currency",
|
||||
currency,
|
||||
signDisplay: "auto",
|
||||
}).format(amount)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Providers only have an ID to identify them. This function formats the ID
|
||||
* into a human-readable string.
|
||||
*
|
||||
* Format example: pp_stripe-blik_dkk
|
||||
*
|
||||
* @param id - The ID of the provider
|
||||
* @returns A formatted string
|
||||
*/
|
||||
export const formatProvider = (id: string) => {
|
||||
const [_, name, type] = id.split("_")
|
||||
return (
|
||||
name
|
||||
.split("-")
|
||||
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
||||
.join(" ") + (type ? ` (${type.toUpperCase()})` : "")
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { FetchError } from "@medusajs/js-sdk"
|
||||
|
||||
export const isFetchError = (error: any): error is FetchError => {
|
||||
return error instanceof FetchError
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { currencies } from "./data/currencies"
|
||||
|
||||
export const getDecimalDigits = (currency: string) => {
|
||||
return currencies[currency.toUpperCase()]?.decimal_digits ?? 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted amount based on the currency code using the browser's locale
|
||||
* @param amount - The amount to format
|
||||
* @param currencyCode - The currency code to format the amount in
|
||||
* @returns - The formatted amount
|
||||
*
|
||||
* @example
|
||||
* getFormattedAmount(10, "usd") // '$10.00' if the browser's locale is en-US
|
||||
* getFormattedAmount(10, "usd") // '10,00 $' if the browser's locale is fr-FR
|
||||
*/
|
||||
export const getLocaleAmount = (amount: number, currencyCode: string) => {
|
||||
const formatter = new Intl.NumberFormat([], {
|
||||
style: "currency",
|
||||
currencyDisplay: "narrowSymbol",
|
||||
currency: currencyCode,
|
||||
})
|
||||
|
||||
return formatter.format(amount)
|
||||
}
|
||||
|
||||
export const getNativeSymbol = (currencyCode: string) => {
|
||||
const formatted = new Intl.NumberFormat([], {
|
||||
style: "currency",
|
||||
currency: currencyCode,
|
||||
currencyDisplay: "narrowSymbol",
|
||||
}).format(0)
|
||||
|
||||
return formatted.replace(/\d/g, "").replace(/[.,]/g, "").trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* In some cases we want to display the amount with the currency code and symbol,
|
||||
* in the format of "symbol amount currencyCode". This breaks from the
|
||||
* user's locale and is only used in cases where we want to display the
|
||||
* currency code and symbol explicitly, e.g. for totals.
|
||||
*/
|
||||
export const getStylizedAmount = (amount: number, currencyCode: string) => {
|
||||
const symbol = getNativeSymbol(currencyCode)
|
||||
const decimalDigits = getDecimalDigits(currencyCode)
|
||||
|
||||
const total = amount.toLocaleString(undefined, {
|
||||
minimumFractionDigits: decimalDigits,
|
||||
maximumFractionDigits: decimalDigits,
|
||||
})
|
||||
|
||||
return `${symbol} ${total} ${currencyCode.toUpperCase()}`
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { TFunction } from "i18next"
|
||||
|
||||
export const getOrderPaymentStatus = (
|
||||
t: TFunction<"translation">,
|
||||
status: string
|
||||
) => {
|
||||
const [label, color] = {
|
||||
not_paid: [t("orders.payment.status.notPaid"), "red"],
|
||||
authorized: [t("orders.payment.status.authorized"), "orange"],
|
||||
partially_authorized: [
|
||||
t("orders.payment.status.partiallyAuthorized"),
|
||||
"red",
|
||||
],
|
||||
awaiting: [t("orders.payment.status.awaiting"), "orange"],
|
||||
captured: [t("orders.payment.status.captured"), "green"],
|
||||
refunded: [t("orders.payment.status.refunded"), "green"],
|
||||
partially_refunded: [
|
||||
t("orders.payment.status.partiallyRefunded"),
|
||||
"orange",
|
||||
],
|
||||
partially_captured: [
|
||||
t("orders.payment.status.partiallyCaptured"),
|
||||
"orange",
|
||||
],
|
||||
canceled: [t("orders.payment.status.canceled"), "red"],
|
||||
requires_action: [t("orders.payment.status.requiresAction"), "orange"],
|
||||
}[status]
|
||||
|
||||
return { label, color }
|
||||
}
|
||||
|
||||
export const getOrderFulfillmentStatus = (
|
||||
t: TFunction<"translation">,
|
||||
status: string
|
||||
) => {
|
||||
const [label, color] = {
|
||||
not_fulfilled: [t("orders.fulfillment.status.notFulfilled"), "red"],
|
||||
partially_fulfilled: [
|
||||
t("orders.fulfillment.status.partiallyFulfilled"),
|
||||
"orange",
|
||||
],
|
||||
fulfilled: [t("orders.fulfillment.status.fulfilled"), "green"],
|
||||
partially_shipped: [
|
||||
t("orders.fulfillment.status.partiallyShipped"),
|
||||
"orange",
|
||||
],
|
||||
shipped: [t("orders.fulfillment.status.shipped"), "green"],
|
||||
partially_returned: [
|
||||
t("orders.fulfillment.status.partiallyReturned"),
|
||||
"orange",
|
||||
],
|
||||
returned: [t("orders.fulfillment.status.returned"), "green"],
|
||||
canceled: [t("orders.fulfillment.status.canceled"), "red"],
|
||||
requires_action: [t("orders.fulfillment.status.requiresAction"), "orange"],
|
||||
}[status] as [string, "red" | "orange" | "green"]
|
||||
|
||||
return { label, color }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { OrderLineItemDTO } from "@medusajs/types"
|
||||
|
||||
export const getFulfillableQuantity = (item: OrderLineItemDTO) => {
|
||||
return item.quantity - item.detail.fulfilled_quantity
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { AdminPaymentCollection } from "@medusajs/types"
|
||||
|
||||
export const getTotalCaptured = (
|
||||
paymentCollections: AdminPaymentCollection[]
|
||||
) =>
|
||||
paymentCollections.reduce((acc, paymentCollection) => {
|
||||
acc =
|
||||
acc +
|
||||
((paymentCollection.captured_amount as number) -
|
||||
(paymentCollection.refunded_amount as number))
|
||||
return acc
|
||||
}, 0)
|
||||
|
||||
export const getTotalPending = (paymentCollections: AdminPaymentCollection[]) =>
|
||||
paymentCollections.reduce((acc, paymentCollection) => {
|
||||
acc +=
|
||||
(paymentCollection.amount as number) -
|
||||
(paymentCollection.captured_amount as number)
|
||||
|
||||
return acc
|
||||
}, 0)
|
||||
@@ -0,0 +1,27 @@
|
||||
const formatter = new Intl.NumberFormat([], {
|
||||
style: "percent",
|
||||
minimumFractionDigits: 2,
|
||||
})
|
||||
|
||||
/**
|
||||
* Formats a number as a percentage
|
||||
* @param value - The value to format
|
||||
* @param isPercentageValue - Whether the value is already a percentage value (where `0` is 0%, `0.5` is 50%, `0.75` is 75%, etc). Defaults to false
|
||||
* @returns The formatted percentage in the form of a localized string
|
||||
*
|
||||
* @example
|
||||
* formatPercentage(0.5, true) // "50%"
|
||||
* formatPercentage(50) // "50%"
|
||||
*/
|
||||
export const formatPercentage = (
|
||||
value?: number | null,
|
||||
isPercentageValue = false
|
||||
) => {
|
||||
let val = value || 0
|
||||
|
||||
if (!isPercentageValue) {
|
||||
val = val / 100
|
||||
}
|
||||
|
||||
return formatter.format(val)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { PromotionDTO } from "@medusajs/types"
|
||||
|
||||
export enum PromotionStatus {
|
||||
SCHEDULED = "SCHEDULED",
|
||||
EXPIRED = "EXPIRED",
|
||||
ACTIVE = "ACTIVE",
|
||||
DISABLED = "DISABLED",
|
||||
}
|
||||
|
||||
export const getPromotionStatus = (promotion: PromotionDTO) => {
|
||||
const date = new Date()
|
||||
const campaign = promotion.campaign
|
||||
|
||||
if (!campaign) {
|
||||
return PromotionStatus.ACTIVE
|
||||
}
|
||||
|
||||
if (new Date(campaign.starts_at!) > date) {
|
||||
return PromotionStatus.SCHEDULED
|
||||
}
|
||||
|
||||
const campaignBudget = campaign.budget
|
||||
const overBudget =
|
||||
campaignBudget && campaignBudget.used! > campaignBudget.limit!
|
||||
|
||||
if ((campaign.ends_at && new Date(campaign.ends_at) < date) || overBudget) {
|
||||
return PromotionStatus.EXPIRED
|
||||
}
|
||||
|
||||
return PromotionStatus.ACTIVE
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { QueryClient } from "@tanstack/react-query"
|
||||
|
||||
export const MEDUSA_BACKEND_URL = __BACKEND_URL__ ?? "http://localhost:9000"
|
||||
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: 90000,
|
||||
retry: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,54 @@
|
||||
import { QueryKey, UseQueryOptions } from "@tanstack/react-query"
|
||||
|
||||
export type TQueryKey<TKey, TListQuery = any, TDetailQuery = string> = {
|
||||
all: readonly [TKey]
|
||||
lists: () => readonly [...TQueryKey<TKey>["all"], "list"]
|
||||
list: (
|
||||
query?: TListQuery
|
||||
) => readonly [
|
||||
...ReturnType<TQueryKey<TKey>["lists"]>,
|
||||
{ query: TListQuery | undefined },
|
||||
]
|
||||
details: () => readonly [...TQueryKey<TKey>["all"], "detail"]
|
||||
detail: (
|
||||
id: TDetailQuery,
|
||||
query?: TListQuery
|
||||
) => readonly [
|
||||
...ReturnType<TQueryKey<TKey>["details"]>,
|
||||
TDetailQuery,
|
||||
{ query: TListQuery | undefined },
|
||||
]
|
||||
}
|
||||
|
||||
export type UseQueryOptionsWrapper<
|
||||
// Return type of queryFn
|
||||
TQueryFn = unknown,
|
||||
// Type thrown in case the queryFn rejects
|
||||
E = Error,
|
||||
// Query key type
|
||||
TQueryKey extends QueryKey = QueryKey,
|
||||
> = Omit<
|
||||
UseQueryOptions<TQueryFn, E, TQueryFn, TQueryKey>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
|
||||
export const queryKeysFactory = <
|
||||
T,
|
||||
TListQueryType = any,
|
||||
TDetailQueryType = string,
|
||||
>(
|
||||
globalKey: T
|
||||
) => {
|
||||
const queryKeyFactory: TQueryKey<T, TListQueryType, TDetailQueryType> = {
|
||||
all: [globalKey],
|
||||
lists: () => [...queryKeyFactory.all, "list"],
|
||||
list: (query?: TListQueryType) => [...queryKeyFactory.lists(), { query }],
|
||||
details: () => [...queryKeyFactory.all, "detail"],
|
||||
detail: (id: TDetailQueryType, query?: TListQueryType) => [
|
||||
...queryKeyFactory.details(),
|
||||
id,
|
||||
{ query },
|
||||
],
|
||||
}
|
||||
return queryKeyFactory
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { AdminOrderLineItem } from "@medusajs/types"
|
||||
|
||||
export function getReturnableQuantity(item: AdminOrderLineItem): number {
|
||||
const {
|
||||
shipped_quantity,
|
||||
return_received_quantity,
|
||||
return_dismissed_quantity,
|
||||
return_requested_quantity,
|
||||
} = item.detail
|
||||
|
||||
return (
|
||||
shipped_quantity -
|
||||
(return_received_quantity +
|
||||
return_requested_quantity +
|
||||
return_dismissed_quantity)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import i18n from "i18next"
|
||||
import { z } from "zod"
|
||||
|
||||
export const AddressSchema = z.object({
|
||||
first_name: z.string().min(1),
|
||||
last_name: z.string().min(1),
|
||||
company: z.string().optional(),
|
||||
address_1: z.string().min(1),
|
||||
address_2: z.string().optional(),
|
||||
city: z.string().min(1),
|
||||
postal_code: z.string().min(1),
|
||||
province: z.string().optional(),
|
||||
country_code: z.string().min(1),
|
||||
phone: z.string().optional(),
|
||||
})
|
||||
|
||||
export const EmailSchema = z.object({
|
||||
email: z.string().email(),
|
||||
})
|
||||
|
||||
export const TransferOwnershipSchema = z
|
||||
.object({
|
||||
current_owner_id: z.string().min(1),
|
||||
new_owner_id: z
|
||||
.string()
|
||||
.min(1, i18n.t("transferOwnership.validation.required")),
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (data.current_owner_id === data.new_owner_id) {
|
||||
return ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ["new_owner_id"],
|
||||
message: i18n.t("transferOwnership.validation.mustBeDifferent"),
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
|
||||
export function isReturnOption(shippingOption: HttpTypes.AdminShippingOption) {
|
||||
return !!shippingOption.rules?.find(
|
||||
(r) =>
|
||||
r.attribute === "is_return" && r.value === "true" && r.operator === "eq"
|
||||
)
|
||||
}
|
||||
|
||||
export function isOptionEnabledInStore(
|
||||
shippingOption: HttpTypes.AdminShippingOption
|
||||
) {
|
||||
return !!shippingOption.rules?.find(
|
||||
(r) =>
|
||||
r.attribute === "enabled_in_store" &&
|
||||
r.value === "true" &&
|
||||
r.operator === "eq"
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export const MEDUSA_STOREFRONT_URL =
|
||||
__STOREFRONT_URL__ ?? "http://localhost:8000"
|
||||
@@ -0,0 +1,47 @@
|
||||
import i18next from "i18next"
|
||||
import { z } from "zod"
|
||||
import { castNumber } from "./cast-number"
|
||||
|
||||
/**
|
||||
* Validates that an optional value is an integer.
|
||||
*/
|
||||
export const optionalInt = z
|
||||
.union([z.string(), z.number()])
|
||||
.optional()
|
||||
.refine(
|
||||
(value) => {
|
||||
if (value === "" || value === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
return Number.isInteger(castNumber(value))
|
||||
},
|
||||
{
|
||||
message: i18next.t("validation.mustBeInt"),
|
||||
}
|
||||
)
|
||||
.refine(
|
||||
(value) => {
|
||||
if (value === "" || value === undefined) {
|
||||
return true
|
||||
}
|
||||
|
||||
return castNumber(value) >= 0
|
||||
},
|
||||
{
|
||||
message: i18next.t("validation.mustBePositive"),
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Schema for metadata form.
|
||||
*/
|
||||
export const metadataFormSchema = z.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
value: z.unknown(),
|
||||
isInitial: z.boolean().optional(),
|
||||
isDeleted: z.boolean().optional(),
|
||||
isIgnored: z.boolean().optional(),
|
||||
})
|
||||
)
|
||||
Reference in New Issue
Block a user