@techsio/storefront-data
Version:
Medusa-first storefront data layer built on TanStack Query.
152 lines (151 loc) • 5.67 kB
JavaScript
import { toComparableTimestamp } from "../shared/date-utils.js";
import { isAuthError } from "../shared/medusa-errors.js";
const normalizeComparableString = (value, lowercase = false)=>{
if ("string" != typeof value) return;
const normalized = value.trim();
if (!normalized) return;
return lowercase ? normalized.toLowerCase() : normalized;
};
const pickNewestAddress = (addresses)=>{
if (0 === addresses.length) return;
return [
...addresses
].sort((left, right)=>{
const rightCreatedAt = toComparableTimestamp(right.created_at);
const leftCreatedAt = toComparableTimestamp(left.created_at);
if (rightCreatedAt !== leftCreatedAt) return rightCreatedAt - leftCreatedAt;
const rightUpdatedAt = toComparableTimestamp(right.updated_at);
const leftUpdatedAt = toComparableTimestamp(left.updated_at);
return rightUpdatedAt - leftUpdatedAt;
})[0];
};
const addressMatchesCreateInput = (address, input)=>{
const stringComparisons = [
{
key: "first_name"
},
{
key: "last_name"
},
{
key: "company"
},
{
key: "address_1"
},
{
key: "address_2"
},
{
key: "city"
},
{
key: "province"
},
{
key: "postal_code"
},
{
key: "country_code",
lowercase: true
},
{
key: "phone"
}
];
for (const comparison of stringComparisons){
const expected = normalizeComparableString(input[comparison.key], comparison.lowercase);
if (void 0 === expected) continue;
const actual = normalizeComparableString(address[comparison.key], comparison.lowercase);
if (actual !== expected) return false;
}
const booleanComparisons = [
"is_default_shipping",
"is_default_billing"
];
for (const key of booleanComparisons){
const expected = input[key];
if ("boolean" != typeof expected) continue;
const actual = address[key];
if (actual !== expected) return false;
}
return true;
};
const getAddressIdSet = (addresses)=>new Set(addresses.map((address)=>address.id).filter((id)=>Boolean(id)));
const pickSingleOrNewestAddress = (addresses)=>{
if (1 === addresses.length) return addresses[0];
if (addresses.length > 1) return pickNewestAddress(addresses);
};
const getNewlyCreatedAddresses = (addresses, existingAddressIds)=>addresses.filter((address)=>"string" == typeof address.id && !existingAddressIds.has(address.id));
const resolveCreatedAddress = (addresses, params, existingAddressIds)=>{
if (existingAddressIds) {
const newlyCreatedAddress = pickSingleOrNewestAddress(getNewlyCreatedAddresses(addresses, existingAddressIds));
if (newlyCreatedAddress) return newlyCreatedAddress;
}
const matchingAddress = pickSingleOrNewestAddress(addresses.filter((address)=>addressMatchesCreateInput(address, params)));
if (matchingAddress) return matchingAddress;
return pickNewestAddress(addresses);
};
function createMedusaCustomerService(sdk) {
const fetchAllCustomerAddresses = async ()=>{
const pageSize = 100;
const addresses = [];
let offset = 0;
while(true){
const response = await sdk.store.customer.listAddress({
limit: pageSize,
offset
});
const page = response.addresses ?? [];
addresses.push(...page);
if (0 === page.length) break;
offset += page.length;
if ("number" == typeof response.count && offset >= response.count) break;
if ("number" != typeof response.count && page.length < pageSize) break;
}
return addresses;
};
return {
async getAddresses (_params, signal) {
try {
const response = await sdk.client.fetch("/store/customers/me/addresses", {
signal
});
return {
addresses: response.addresses ?? []
};
} catch (error) {
if (isAuthError(error)) return {
addresses: []
};
throw error;
}
},
async createAddress (params) {
let existingAddressIds = null;
try {
existingAddressIds = getAddressIdSet(await fetchAllCustomerAddresses());
} catch {}
const { customer } = await sdk.store.customer.createAddress(params);
const addresses = customer.addresses ?? [];
const createdAddress = resolveCreatedAddress(addresses, params, existingAddressIds);
if (createdAddress) return createdAddress;
throw new Error("Failed to create address");
},
async updateAddress (addressId, params) {
const { customer } = await sdk.store.customer.updateAddress(addressId, params);
const addresses = customer.addresses ?? [];
const address = addresses.find((a)=>a.id === addressId);
if (!address) throw new Error("Failed to update address");
return address;
},
async deleteAddress (addressId) {
await sdk.store.customer.deleteAddress(addressId);
},
async updateCustomer (params) {
const { customer } = await sdk.store.customer.update(params);
return customer;
}
};
}
export { createMedusaCustomerService };