@salla.sa/twilight-components
Version:
Salla Web Component
136 lines (135 loc) • 6.04 kB
JavaScript
/*!
* Crafted with ❤ by Salla
*/
/**
* API Service for salla-bullet-delivery component
* Uses Salla's shipping API and scope API for delivery location management
*/
const API_LOG_PREFIX = 'BulletDeliveryAPI';
const validId = (id) => {
const n = id == null ? Number.NaN : Number(id);
return !Number.isNaN(n) && n !== 0;
};
async function withApiErrorHandling(fn, fallback, logLabel) {
try {
return await fn();
}
catch (error) {
console.error(`${API_LOG_PREFIX}: ${logLabel}`, error);
return fallback;
}
}
/** Uses country code from API (e.g. 'SA'). */
export const isSaudiArabia = (countryCode) => String(countryCode).toUpperCase() === 'SA';
/**
* Fast Delivery API Service
* Uses Salla's shipping API and scopes API. Branch and address data are used as returned by the API (no mapping).
*/
export const bulletDeliveryAPI = {
/**
* Get available countries from Salla shipping API
* @param forBranch - when true, use for_branch=1 (e.g. for pickup/branches tab)
*/
async getCountries(forBranch = false) {
return withApiErrorHandling(async () => {
const data = (await salla.api.request("shipping/countries", { params: { for_branch: forBranch ? 1 : 0 } }))?.data ?? [];
return data.map((c) => ({ id: c.id, code: c.code, name: c.name, has_regions: isSaudiArabia(c.code) }));
}, [], 'Error getting countries');
},
/**
* Get regions for a country from Salla shipping API
* Endpoint: GET /shipping/countries/<COUNTRY_ID>/region
*/
async getRegions(countryId) {
if (!validId(countryId)) {
console.warn(`${API_LOG_PREFIX}: getRegions called without valid country_id`);
return [];
}
return withApiErrorHandling(async () => {
const data = (await salla.api.request(`shipping/countries/${countryId}/regions`))?.data ?? [];
return data.map((r) => ({ id: r.id, name: r.name, code: r.code, country_id: Number(countryId) }));
}, [], 'Error fetching regions');
},
/**
* Get cities from Salla shipping API
* @param regionId - Optional; when provided (e.g. for SA), cities are filtered by region
*/
async getCities(countryId, regionId) {
if (!validId(countryId)) {
console.warn(`${API_LOG_PREFIX}: getCities called without valid country_id`);
return [];
}
return withApiErrorHandling(async () => {
const params = { for_branch: 0, country_id: countryId };
if (regionId)
params.region_id = regionId;
const data = (await salla.api.request("shipping/cities", { params }))?.data ?? [];
return data.map((c) => ({ id: c.id, name: c.name, country_id: countryId, ...(c.region_id != null && { region_id: c.region_id }) }));
}, [], 'Error fetching cities');
},
/**
* Get districts from Salla shipping API
*/
async getDistricts(cityId) {
if (!validId(cityId)) {
console.warn(`${API_LOG_PREFIX}: getDistricts called without valid city_id`);
return [];
}
return withApiErrorHandling(async () => {
const raw = (await salla.api.request("shipping/districts", { params: { for_branch: 0, city_id: cityId } }))?.data;
const list = Array.isArray(raw) ? raw : (Array.isArray(raw?.districts) ? raw.districts : []);
return list.map((d) => ({ id: d.id, name: d.name, name_en: d.name_en, city_id: cityId }));
}, [], 'Error fetching districts');
},
async getSavedAddresses() {
return withApiErrorHandling(async () => {
const data = (await salla.api.request("address"))?.data;
return Array.isArray(data) ? data : [];
}, [], 'Error fetching user addresses');
},
async getBranches({ query, lat, lng, country_id, per_page = 20 } = {}) {
return withApiErrorHandling(async () => {
const params = { per_page };
if (query?.trim().length >= 2)
params.query = query;
if (lat)
params.lat = lat;
if (lng)
params.lng = lng;
if (country_id)
params.country_id = country_id;
const res = await salla.api.request("branches", { params });
return (Array.isArray(res?.data) ? res.data : []);
}, [], 'Error fetching branches');
},
async saveAddressLocation(payload) {
return withApiErrorHandling(async () => {
const res = await salla.api.request('address/location', { ...payload, for_allocation: true }, 'post');
const data = res?.data ?? res;
const address = typeof data === 'object' && data != null && 'id' in data ? data : undefined;
return { success: true, address };
}, { success: false }, 'Error saving address/location');
},
async setDeliveryScope(scopeId) {
return withApiErrorHandling(async () => {
await salla.scope.change({ id: scopeId });
salla.storage.set("scope", { ...(salla.storage.get("scope") || {}), id: scopeId });
return true;
}, false, 'Error setting delivery scope');
},
async allocateScope(payload) {
const errMsg = (d) => d?.error?.message ?? d?.message ?? 'Failed to allocate scope';
try {
const response = await salla.api.request("scopes/allocation", payload, 'post');
// SDK resolves with { data } and throws on non-2xx; any resolved value is success
const data = response?.data ?? response;
return { success: true, data: data };
}
catch (error) {
console.error(`${API_LOG_PREFIX}: Error allocating scope`, error);
const err = error;
return { success: false, error: err?.response?.data != null ? errMsg(err.response.data) : (err?.message ?? 'Unknown error') };
}
},
};
export default bulletDeliveryAPI;