base commit
This commit is contained in:
@@ -2,3 +2,8 @@
|
||||
export const apiBaseURL = import.meta.env.VITE_API_URL ?? '/api'
|
||||
|
||||
export const STORE_NAME = 'Рукодельная лавка'
|
||||
|
||||
/** Демо-контакты для футера; при необходимости задайте через VITE_* в `.env`. */
|
||||
export const STORE_EMAIL = import.meta.env.VITE_STORE_EMAIL ?? 'hello@example.com'
|
||||
export const STORE_PHONE = import.meta.env.VITE_STORE_PHONE ?? '+7 (900) 000-00-00'
|
||||
export const STORE_SOCIAL_NOTE = import.meta.env.VITE_STORE_SOCIAL_NOTE ?? 'Соцсети: укажите ссылки при публикации'
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
export const ORDER_STATUSES = [
|
||||
'DRAFT',
|
||||
'PENDING_PAYMENT',
|
||||
'PAYMENT_VERIFICATION',
|
||||
'PAID',
|
||||
'IN_PROGRESS',
|
||||
'SHIPPED',
|
||||
'READY_FOR_PICKUP',
|
||||
'DONE',
|
||||
'CANCELLED',
|
||||
] as const
|
||||
|
||||
export type OrderStatus = (typeof ORDER_STATUSES)[number]
|
||||
|
||||
export const ORDER_STATUS_TRANSITIONS: Record<OrderStatus, OrderStatus[]> = {
|
||||
DRAFT: ['PENDING_PAYMENT', 'CANCELLED'],
|
||||
PENDING_PAYMENT: ['PAID', 'CANCELLED'],
|
||||
PAID: ['IN_PROGRESS', 'CANCELLED'],
|
||||
IN_PROGRESS: ['SHIPPED', 'CANCELLED'],
|
||||
SHIPPED: ['DONE'],
|
||||
DONE: [],
|
||||
CANCELLED: [],
|
||||
/** Следующие статусы, доступные админу (смена через PATCH). */
|
||||
export function getAdminNextOrderStatuses(status: string, deliveryType: 'delivery' | 'pickup'): OrderStatus[] {
|
||||
switch (status) {
|
||||
case 'DRAFT':
|
||||
return ['PENDING_PAYMENT', 'CANCELLED']
|
||||
case 'PENDING_PAYMENT':
|
||||
return ['CANCELLED']
|
||||
case 'PAYMENT_VERIFICATION':
|
||||
return ['PAID', 'CANCELLED']
|
||||
case 'PAID':
|
||||
return ['IN_PROGRESS', 'CANCELLED']
|
||||
case 'IN_PROGRESS':
|
||||
if (deliveryType === 'delivery') return ['SHIPPED', 'CANCELLED']
|
||||
return ['READY_FOR_PICKUP', 'CANCELLED']
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export function canTransitionOrderStatus(from: string, to: string): boolean {
|
||||
if (from === to) return true
|
||||
const f = from as OrderStatus
|
||||
const list = ORDER_STATUS_TRANSITIONS[f]
|
||||
return Array.isArray(list) ? list.includes(to as OrderStatus) : false
|
||||
return getAdminNextOrderStatuses(from, 'delivery').includes(to as OrderStatus)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
const KEY = 'craftshop_admin_token'
|
||||
const TOKEN_EVENT = 'craftshop_admin_token_change'
|
||||
|
||||
export function getAdminToken(): string | null {
|
||||
return sessionStorage.getItem(KEY)
|
||||
}
|
||||
|
||||
function notifyTokenListeners(): void {
|
||||
window.dispatchEvent(new Event(TOKEN_EVENT))
|
||||
}
|
||||
|
||||
/** Подписаться на смену токена (в т. ч. после setAdminToken). */
|
||||
export function subscribeAdminTokenChange(cb: () => void): () => void {
|
||||
window.addEventListener(TOKEN_EVENT, cb)
|
||||
return () => window.removeEventListener(TOKEN_EVENT, cb)
|
||||
}
|
||||
|
||||
export function setAdminToken(token: string): void {
|
||||
sessionStorage.setItem(KEY, token)
|
||||
notifyTokenListeners()
|
||||
}
|
||||
|
||||
export function clearAdminToken(): void {
|
||||
sessionStorage.removeItem(KEY)
|
||||
notifyTokenListeners()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { apiBaseURL } from '@/shared/config'
|
||||
|
||||
/** Абсолютный или корневой путь начала OAuth на бэкенде (редирект браузера). */
|
||||
export function oauthAuthorizeUrl(provider: 'vk' | 'yandex'): string {
|
||||
const base = apiBaseURL.replace(/\/$/, '')
|
||||
return `${base}/auth/oauth/${provider}`
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/** Человекочитаемые подписи к кодам статуса заказа */
|
||||
export function orderStatusLabelRu(code: string): string {
|
||||
const map: Record<string, string> = {
|
||||
DRAFT: 'Черновик',
|
||||
PENDING_PAYMENT: 'Ожидает оплаты',
|
||||
PAYMENT_VERIFICATION: 'Проверка оплаты',
|
||||
PAID: 'Оплачен',
|
||||
IN_PROGRESS: 'В работе',
|
||||
SHIPPED: 'Отправлен',
|
||||
READY_FOR_PICKUP: 'Готово к получению',
|
||||
DONE: 'Завершён',
|
||||
CANCELLED: 'Отменён',
|
||||
}
|
||||
return map[code] ?? code
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/** Склонение «N отзыв(ов…)» для целых n ≥ 0. */
|
||||
export function reviewsCountRu(n: number): string {
|
||||
const x = Math.abs(Math.floor(n))
|
||||
const mod100 = x % 100
|
||||
const mod10 = x % 10
|
||||
let word = 'отзывов'
|
||||
if (mod100 < 11 || mod100 > 14) {
|
||||
if (mod10 === 1) word = 'отзыв'
|
||||
else if (mod10 >= 2 && mod10 <= 4) word = 'отзыва'
|
||||
}
|
||||
return `${x}\u00a0${word}`
|
||||
}
|
||||
Reference in New Issue
Block a user