feat(tariffs): configurable purchase order for periods and packages
The order of enabled_periods (period tariffs) and traffic_packages (traffic tariffs) is now the storefront order everywhere — both the Telegram keyboard and the web app. Only new tariffs-config tariffs are affected; legacy subscription/traffic options are untouched. - Stop sorting periods and traffic packages in the web app plans serializer so it follows the configured order, matching the bot keyboards that already iterate the lists as-is. - Preserve the row order through the admin draft (load and save) instead of sorting by months. - Add a reusable Sortable component to the UI library (native HTML5 drag & drop with a grip handle; bits-ui/shadcn have no such primitive) and use it to reorder period rows and traffic package rows in the tariff editor.
This commit is contained in:
@@ -303,6 +303,24 @@ export function createTariffsStore({ api, onTariffsSaved, flash, at }) {
|
||||
}));
|
||||
}
|
||||
|
||||
function moveDraftRow(field, fromIndex, toIndex) {
|
||||
state.update((s) => {
|
||||
const rows = [...(s.tariffDraft[field] || [])];
|
||||
if (
|
||||
fromIndex === toIndex ||
|
||||
fromIndex < 0 ||
|
||||
toIndex < 0 ||
|
||||
fromIndex >= rows.length ||
|
||||
toIndex >= rows.length
|
||||
) {
|
||||
return s;
|
||||
}
|
||||
const [moved] = rows.splice(fromIndex, 1);
|
||||
rows.splice(toIndex, 0, moved);
|
||||
return { ...s, tariffDraft: { ...s.tariffDraft, [field]: rows } };
|
||||
});
|
||||
}
|
||||
|
||||
function updateState(updates) {
|
||||
state.update((s) => ({ ...s, ...updates }));
|
||||
}
|
||||
@@ -326,5 +344,6 @@ export function createTariffsStore({ api, onTariffsSaved, flash, at }) {
|
||||
deleteTariff,
|
||||
addDraftRow,
|
||||
removeDraftRow,
|
||||
moveDraftRow,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -69,6 +69,8 @@ export function rowsFromPackages(packageSet, currency, valueKey) {
|
||||
export function draftFromTariff(tariff, defaultCurrency = "rub") {
|
||||
const currency = normalizeCurrencyKey(defaultCurrency);
|
||||
const defaultPrices = tariff.prices?.[currency] || {};
|
||||
// enabled_periods comes first so its order (the configured purchase order)
|
||||
// is preserved; any extra price-only months are appended afterwards.
|
||||
const months = new Set([
|
||||
...(tariff.enabled_periods || []),
|
||||
...Object.keys(defaultPrices).map(Number),
|
||||
@@ -77,7 +79,6 @@ export function draftFromTariff(tariff, defaultCurrency = "rub") {
|
||||
]);
|
||||
const periodRows = [...months]
|
||||
.filter((month) => Number.isFinite(month) && month > 0)
|
||||
.sort((a, b) => a - b)
|
||||
.map((month) => ({
|
||||
months: month,
|
||||
rub:
|
||||
@@ -231,8 +232,7 @@ export function tariffFromDraft(draft, fallbackCurrency = "rub") {
|
||||
if (seenMonths.has(row.months)) return false;
|
||||
seenMonths.add(row.months);
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) => a.months - b.months);
|
||||
});
|
||||
tariff.monthly_gb = parseNumber(draft.monthly_gb, 0);
|
||||
tariff.enabled_periods = rows.map((row) => row.months);
|
||||
const defaultPrices = Object.fromEntries(rows.map((row) => [String(row.months), row.rub || 0]));
|
||||
|
||||
Reference in New Issue
Block a user