Initial commit of Balout Pastry admin dashboards.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
export type Category = {
|
||||
id: string
|
||||
nameFa: string
|
||||
nameEn: string
|
||||
children: Category[]
|
||||
}
|
||||
|
||||
export const initialCategories: Category[] = [
|
||||
{
|
||||
id: '1',
|
||||
nameFa: 'شیرینی',
|
||||
nameEn: 'Pastries',
|
||||
children: [
|
||||
{
|
||||
id: '1-1',
|
||||
nameFa: 'شیرینی خشک',
|
||||
nameEn: 'Dry Cookies',
|
||||
children: [
|
||||
{
|
||||
id: '1-1-1',
|
||||
nameFa: 'شیرینی پسته',
|
||||
nameEn: 'Pistachio Cookie',
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
id: '1-1-2',
|
||||
nameFa: 'شیرینی گردو',
|
||||
nameEn: 'Walnut Cookie',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1-2',
|
||||
nameFa: 'شیرینی تر',
|
||||
nameEn: 'Soft Pastries',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
nameFa: 'کیک',
|
||||
nameEn: 'Cakes',
|
||||
children: [
|
||||
{
|
||||
id: '2-1',
|
||||
nameFa: 'کیک شکلاتی',
|
||||
nameEn: 'Chocolate Cake',
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
id: '2-2',
|
||||
nameFa: 'چیزکیک',
|
||||
nameEn: 'Cheesecake',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
nameFa: 'نان',
|
||||
nameEn: 'Bread',
|
||||
children: [
|
||||
{
|
||||
id: '3-1',
|
||||
nameFa: 'کروسان',
|
||||
nameEn: 'Croissant',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
nameFa: 'باقلوا',
|
||||
nameEn: 'Baklava',
|
||||
children: [],
|
||||
},
|
||||
]
|
||||
|
||||
export function createCategory(nameFa: string, nameEn: string): Category {
|
||||
return {
|
||||
id: `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||
nameFa,
|
||||
nameEn,
|
||||
children: [],
|
||||
}
|
||||
}
|
||||
|
||||
export function addChildCategory(
|
||||
categories: Category[],
|
||||
parentId: string,
|
||||
child: Category,
|
||||
): Category[] {
|
||||
return categories.map((category) => {
|
||||
if (category.id === parentId) {
|
||||
return { ...category, children: [...category.children, child] }
|
||||
}
|
||||
if (category.children.length > 0) {
|
||||
return {
|
||||
...category,
|
||||
children: addChildCategory(category.children, parentId, child),
|
||||
}
|
||||
}
|
||||
return category
|
||||
})
|
||||
}
|
||||
|
||||
export function removeCategory(
|
||||
categories: Category[],
|
||||
targetId: string,
|
||||
): Category[] {
|
||||
return categories
|
||||
.filter((category) => category.id !== targetId)
|
||||
.map((category) => ({
|
||||
...category,
|
||||
children: removeCategory(category.children, targetId),
|
||||
}))
|
||||
}
|
||||
|
||||
export function flattenCategories(
|
||||
categories: Category[],
|
||||
prefix = '',
|
||||
): { id: string; labelFa: string; labelEn: string }[] {
|
||||
return categories.flatMap((category) => {
|
||||
const labelFa = prefix ? `${prefix} / ${category.nameFa}` : category.nameFa
|
||||
const labelEn = prefix ? `${prefix} / ${category.nameEn}` : category.nameEn
|
||||
return [
|
||||
{ id: category.id, labelFa, labelEn },
|
||||
...flattenCategories(category.children, labelFa),
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
export function findCategory(
|
||||
categories: Category[],
|
||||
id: string,
|
||||
): Category | null {
|
||||
for (const category of categories) {
|
||||
if (category.id === id) return category
|
||||
const found = findCategory(category.children, id)
|
||||
if (found) return found
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function findParentId(
|
||||
categories: Category[],
|
||||
targetId: string,
|
||||
parentId: string | null = null,
|
||||
): string | null | undefined {
|
||||
for (const category of categories) {
|
||||
if (category.id === targetId) return parentId
|
||||
const found = findParentId(category.children, targetId, category.id)
|
||||
if (found !== undefined) return found
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function updateCategory(
|
||||
categories: Category[],
|
||||
targetId: string,
|
||||
updates: { nameFa: string; nameEn: string },
|
||||
): Category[] {
|
||||
return categories.map((category) => {
|
||||
if (category.id === targetId) {
|
||||
return { ...category, ...updates }
|
||||
}
|
||||
if (category.children.length > 0) {
|
||||
return {
|
||||
...category,
|
||||
children: updateCategory(category.children, targetId, updates),
|
||||
}
|
||||
}
|
||||
return category
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/** Districts of Qom used across settings (shipping, branches). */
|
||||
export const districts = [
|
||||
'پردیسان',
|
||||
'جعفریه',
|
||||
'زنبیلآباد',
|
||||
'سالاریه',
|
||||
'صفاییه',
|
||||
'عطاران',
|
||||
'انارستان',
|
||||
'بنیاد',
|
||||
'آذر',
|
||||
'هنرستان',
|
||||
'باجک',
|
||||
'دورشهر',
|
||||
'خیابان ارم',
|
||||
'شهرک قدس',
|
||||
'شهرک امام حسن',
|
||||
'شهرک مهدیه',
|
||||
'قلعه کامکار',
|
||||
'نیروگاه',
|
||||
'حرم',
|
||||
'بلوار امین',
|
||||
] as const
|
||||
|
||||
export type District = (typeof districts)[number]
|
||||
@@ -0,0 +1,56 @@
|
||||
export type Flavor = {
|
||||
id: string
|
||||
nameFa: string
|
||||
nameEn: string
|
||||
}
|
||||
|
||||
export type FlavorAmountEntry = {
|
||||
id: string
|
||||
amount: string
|
||||
price: number
|
||||
}
|
||||
|
||||
/** One selectable flavor instance on a category (select can be duplicated). */
|
||||
export type FlavorBlock = {
|
||||
id: string
|
||||
flavorId: string
|
||||
entries: FlavorAmountEntry[]
|
||||
}
|
||||
|
||||
export type CategoryFlavorOptions = FlavorBlock[]
|
||||
|
||||
export const flavors: Flavor[] = [
|
||||
{ id: 'chocolate', nameFa: 'شکلات', nameEn: 'Chocolate' },
|
||||
{ id: 'banana', nameFa: 'موز', nameEn: 'Banana' },
|
||||
{ id: 'hazelnut', nameFa: 'فندق', nameEn: 'Hazelnut' },
|
||||
{ id: 'vanilla', nameFa: 'وانیل', nameEn: 'Vanilla' },
|
||||
{ id: 'pistachio', nameFa: 'پسته', nameEn: 'Pistachio' },
|
||||
{ id: 'walnut', nameFa: 'گردو', nameEn: 'Walnut' },
|
||||
{ id: 'strawberry', nameFa: 'توتفرنگی', nameEn: 'Strawberry' },
|
||||
{ id: 'caramel', nameFa: 'کارامل', nameEn: 'Caramel' },
|
||||
]
|
||||
|
||||
function uid() {
|
||||
return `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`
|
||||
}
|
||||
|
||||
export function createFlavorEntry(
|
||||
amount: string,
|
||||
price: number,
|
||||
): FlavorAmountEntry {
|
||||
return {
|
||||
id: uid(),
|
||||
amount,
|
||||
price,
|
||||
}
|
||||
}
|
||||
|
||||
export function createFlavorBlock(flavorId = flavors[0]?.id ?? ''): FlavorBlock {
|
||||
return {
|
||||
id: uid(),
|
||||
flavorId,
|
||||
entries: [],
|
||||
}
|
||||
}
|
||||
|
||||
export { formatPrice } from '../utils/price'
|
||||
@@ -0,0 +1,267 @@
|
||||
import type { SellUnit } from './products'
|
||||
|
||||
export type OrderStatus =
|
||||
| 'pending'
|
||||
| 'confirmed'
|
||||
| 'preparing'
|
||||
| 'ready'
|
||||
| 'delivered'
|
||||
| 'cancelled'
|
||||
|
||||
export type DeliveryType = 'shipping' | 'pickup'
|
||||
|
||||
export type OrderItemOption = {
|
||||
name: string
|
||||
price: number
|
||||
}
|
||||
|
||||
export type OrderItem = {
|
||||
id: string
|
||||
nameFa: string
|
||||
quantity: number
|
||||
unitPrice: number
|
||||
sellUnit: SellUnit
|
||||
options?: OrderItemOption[]
|
||||
}
|
||||
|
||||
export type ShippingAddress = {
|
||||
id: string
|
||||
name: string
|
||||
district: string
|
||||
address: string
|
||||
landline: string
|
||||
}
|
||||
|
||||
export type OrderDelivery =
|
||||
| {
|
||||
type: 'shipping'
|
||||
shippingAddress: ShippingAddress
|
||||
}
|
||||
| {
|
||||
type: 'pickup'
|
||||
branch: string
|
||||
}
|
||||
|
||||
export type Order = {
|
||||
id: string
|
||||
createdAt: string
|
||||
customerName: string
|
||||
customerPhone: string
|
||||
itemCount: number
|
||||
totalPrice: number
|
||||
status: OrderStatus
|
||||
delivery: OrderDelivery
|
||||
items: OrderItem[]
|
||||
note?: string
|
||||
}
|
||||
|
||||
export const orderStatuses: { id: OrderStatus; label: string }[] = [
|
||||
{ id: 'pending', label: 'در انتظار بررسی' },
|
||||
{ id: 'confirmed', label: 'تأیید شده' },
|
||||
{ id: 'preparing', label: 'در حال آمادهسازی' },
|
||||
{ id: 'ready', label: 'آماده تحویل' },
|
||||
{ id: 'delivered', label: 'تحویل شده' },
|
||||
{ id: 'cancelled', label: 'لغو شده' },
|
||||
]
|
||||
|
||||
export const orderStatusLabel: Record<OrderStatus, string> = {
|
||||
pending: 'در انتظار بررسی',
|
||||
confirmed: 'تأیید شده',
|
||||
preparing: 'در حال آمادهسازی',
|
||||
ready: 'آماده تحویل',
|
||||
delivered: 'تحویل شده',
|
||||
cancelled: 'لغو شده',
|
||||
}
|
||||
|
||||
export const deliveryTypeLabel: Record<DeliveryType, string> = {
|
||||
shipping: 'ارسال به',
|
||||
pickup: 'دریافت در محل',
|
||||
}
|
||||
|
||||
export const orderSellUnitLabel: Record<SellUnit, string> = {
|
||||
unit: 'عدد',
|
||||
kilo: 'کیلو',
|
||||
}
|
||||
|
||||
const customers = [
|
||||
{ name: 'سارا محمدی', phone: '09121234567' },
|
||||
{ name: 'علی رضایی', phone: '09129876543' },
|
||||
{ name: 'مریم حسینی', phone: '09351234567' },
|
||||
{ name: 'حسین کریمی', phone: '09123456789' },
|
||||
{ name: 'نازنین احمدی', phone: '09127654321' },
|
||||
{ name: 'رضا نوری', phone: '09361234567' },
|
||||
{ name: 'فاطمه جعفری', phone: '09121112233' },
|
||||
{ name: 'امیر صادقی', phone: '09125556677' },
|
||||
]
|
||||
|
||||
const productNames = [
|
||||
'شیرینی پسته',
|
||||
'کیک شکلاتی',
|
||||
'باقلوا گردو',
|
||||
'نان بربری',
|
||||
'ماکارون',
|
||||
'شیرینی نخودچی',
|
||||
'کیک هویج',
|
||||
'رولت خامه',
|
||||
]
|
||||
|
||||
const optionChoices: OrderItemOption[] = [
|
||||
{ name: 'شکلات اضافه', price: 50000 },
|
||||
{ name: 'بسته کادویی', price: 25000 },
|
||||
{ name: 'نوع شکلات تلخ', price: 40000 },
|
||||
{ name: 'وزن ۱ کیلو', price: 80000 },
|
||||
{ name: 'روکش شکلات', price: 35000 },
|
||||
]
|
||||
|
||||
const branches = ['شعبه مرکزی', 'شعبه صفاییه', 'شعبه نیروی هوایی']
|
||||
|
||||
const shippingAddresses: ShippingAddress[] = [
|
||||
{
|
||||
id: 'addr-1',
|
||||
name: 'منزل',
|
||||
district: 'خیابان ارم',
|
||||
address: 'قم، خیابان ارم، کوچه ۵، پلاک ۱۲',
|
||||
landline: '02531234567',
|
||||
},
|
||||
{
|
||||
id: 'addr-2',
|
||||
name: 'محل کار',
|
||||
district: 'بلوار امین',
|
||||
address: 'قم، بلوار امین، مجتمع تجاری نور، واحد ۴',
|
||||
landline: '02537654321',
|
||||
},
|
||||
{
|
||||
id: 'addr-3',
|
||||
name: 'منزل',
|
||||
district: 'صفاییه',
|
||||
address: 'قم، خیابان شهید بهشتی، پلاک ۸۷',
|
||||
landline: '02531112233',
|
||||
},
|
||||
{
|
||||
id: 'addr-4',
|
||||
name: 'منزل والدین',
|
||||
district: 'حرم',
|
||||
address: 'قم، میدان جهاد، خیابان امام، پلاک ۲۳',
|
||||
landline: '02534445566',
|
||||
},
|
||||
]
|
||||
|
||||
export function formatShippingAddress(address: ShippingAddress) {
|
||||
const landline = address.landline
|
||||
? ` — ${address.landline}`
|
||||
: ''
|
||||
return `${address.name} · ${address.district} — ${address.address}${landline}`
|
||||
}
|
||||
|
||||
const statuses: OrderStatus[] = [
|
||||
'pending',
|
||||
'confirmed',
|
||||
'preparing',
|
||||
'ready',
|
||||
'delivered',
|
||||
'cancelled',
|
||||
]
|
||||
|
||||
export function getItemUnitTotal(item: OrderItem) {
|
||||
const optionsTotal = (item.options ?? []).reduce(
|
||||
(sum, option) => sum + option.price,
|
||||
0,
|
||||
)
|
||||
return item.unitPrice + optionsTotal
|
||||
}
|
||||
|
||||
export function getItemLineTotal(item: OrderItem) {
|
||||
return item.quantity * getItemUnitTotal(item)
|
||||
}
|
||||
|
||||
function buildItems(seed: number): OrderItem[] {
|
||||
const count = (seed % 4) + 1
|
||||
return Array.from({ length: count }, (_, index) => {
|
||||
const name = productNames[(seed + index) % productNames.length]
|
||||
const quantity = ((seed + index) % 3) + 1
|
||||
const unitPrice = [95000, 120000, 185000, 265000, 310000, 420000][
|
||||
(seed + index) % 6
|
||||
]
|
||||
const sellUnit: SellUnit =
|
||||
name.includes('کیک') || name.includes('باقلوا') ? 'kilo' : 'unit'
|
||||
const withOptions = (seed + index) % 3 !== 0
|
||||
const firstOption = optionChoices[(seed + index) % optionChoices.length]
|
||||
const secondOption =
|
||||
optionChoices[(seed + index + 2) % optionChoices.length]
|
||||
const chosenOptions =
|
||||
(seed + index) % 2 === 0 && firstOption.name !== secondOption.name
|
||||
? [firstOption, secondOption]
|
||||
: [firstOption]
|
||||
return {
|
||||
id: `item-${seed}-${index}`,
|
||||
nameFa: name,
|
||||
quantity,
|
||||
unitPrice,
|
||||
sellUnit,
|
||||
options: withOptions ? chosenOptions : undefined,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function buildDelivery(index: number): OrderDelivery {
|
||||
if (index % 2 === 0) {
|
||||
return {
|
||||
type: 'shipping',
|
||||
shippingAddress: shippingAddresses[index % shippingAddresses.length],
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'pickup',
|
||||
branch: branches[index % branches.length],
|
||||
}
|
||||
}
|
||||
|
||||
function buildOrders(): Order[] {
|
||||
return Array.from({ length: 28 }, (_, index) => {
|
||||
const customer = customers[index % customers.length]
|
||||
const items = buildItems(index + 1)
|
||||
const itemCount = items.reduce((sum, item) => sum + item.quantity, 0)
|
||||
const totalPrice = items.reduce(
|
||||
(sum, item) => sum + getItemLineTotal(item),
|
||||
0,
|
||||
)
|
||||
const day = String((index % 28) + 1).padStart(2, '0')
|
||||
const hour = String(10 + (index % 10)).padStart(2, '0')
|
||||
const minute = String((index * 7) % 60).padStart(2, '0')
|
||||
|
||||
return {
|
||||
id: `BL-${1400 + index}`,
|
||||
createdAt: `2026-07-${day}T${hour}:${minute}:00`,
|
||||
customerName: customer.name,
|
||||
customerPhone: customer.phone,
|
||||
itemCount,
|
||||
totalPrice,
|
||||
status: statuses[index % statuses.length],
|
||||
delivery: buildDelivery(index),
|
||||
items,
|
||||
note: index % 5 === 0 ? 'تحویل در ساعت ۱۷' : undefined,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const orders: Order[] = buildOrders()
|
||||
|
||||
export function formatOrderDateTime(iso: string): { date: string; time: string } {
|
||||
const date = new Date(iso)
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return { date: iso, time: '' }
|
||||
}
|
||||
|
||||
const datePart = new Intl.DateTimeFormat('fa-IR', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
}).format(date)
|
||||
|
||||
const timePart = new Intl.DateTimeFormat('fa-IR', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}).format(date)
|
||||
|
||||
return { date: datePart, time: timePart }
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import img1010 from '../images/products/IMG_1010.jpeg'
|
||||
import img1031 from '../images/products/IMG_1031.jpeg'
|
||||
import img1035 from '../images/products/IMG_1035.jpeg'
|
||||
import img1039 from '../images/products/IMG_1039.jpeg'
|
||||
import img1040 from '../images/products/IMG_1040.jpeg'
|
||||
import img1043 from '../images/products/IMG_1043.jpeg'
|
||||
|
||||
export type SellUnit = 'unit' | 'kilo'
|
||||
|
||||
export type ProductOptionValue = {
|
||||
id: string
|
||||
flavorId: string
|
||||
amount: string
|
||||
price: number
|
||||
}
|
||||
|
||||
export type Product = {
|
||||
id: string
|
||||
nameFa: string
|
||||
nameEn: string
|
||||
price: number
|
||||
sellUnit: SellUnit
|
||||
category: string
|
||||
image: string
|
||||
options: ProductOptionValue[]
|
||||
}
|
||||
|
||||
export const productCategories = [
|
||||
'شیرینی',
|
||||
'کیک',
|
||||
'باقلوا',
|
||||
'نان',
|
||||
'ماکارون',
|
||||
] as const
|
||||
|
||||
function optionId() {
|
||||
return `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`
|
||||
}
|
||||
|
||||
export function createProductOptionValue(
|
||||
flavorId: string,
|
||||
amount: string,
|
||||
price: number,
|
||||
): ProductOptionValue {
|
||||
return {
|
||||
id: optionId(),
|
||||
flavorId,
|
||||
amount,
|
||||
price,
|
||||
}
|
||||
}
|
||||
|
||||
export const products: Product[] = [
|
||||
{
|
||||
id: '1',
|
||||
nameFa: 'شیرینی پسته',
|
||||
nameEn: 'Pistachio Cookie',
|
||||
price: 185000,
|
||||
sellUnit: 'unit',
|
||||
category: 'شیرینی',
|
||||
image: img1010,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
nameFa: 'کیک شکلاتی',
|
||||
nameEn: 'Chocolate Cake',
|
||||
price: 420000,
|
||||
sellUnit: 'kilo',
|
||||
category: 'کیک',
|
||||
image: img1031,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
nameFa: 'باقلوا گردو',
|
||||
nameEn: 'Walnut Baklava',
|
||||
price: 265000,
|
||||
sellUnit: 'kilo',
|
||||
category: 'باقلوا',
|
||||
image: img1035,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
nameFa: 'نان خامهای',
|
||||
nameEn: 'Cream Puff',
|
||||
price: 95000,
|
||||
sellUnit: 'unit',
|
||||
category: 'نان',
|
||||
image: img1039,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
nameFa: 'تارت میوه',
|
||||
nameEn: 'Fruit Tart',
|
||||
price: 310000,
|
||||
sellUnit: 'unit',
|
||||
category: 'کیک',
|
||||
image: img1040,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
nameFa: 'ماکارون بلوط',
|
||||
nameEn: 'Balout Macaron',
|
||||
price: 150000,
|
||||
sellUnit: 'unit',
|
||||
category: 'ماکارون',
|
||||
image: img1043,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
nameFa: 'کروسان کرهای',
|
||||
nameEn: 'Butter Croissant',
|
||||
price: 120000,
|
||||
sellUnit: 'unit',
|
||||
category: 'نان',
|
||||
image: img1010,
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
nameFa: 'چیزکیک وانیل',
|
||||
nameEn: 'Vanilla Cheesecake',
|
||||
price: 380000,
|
||||
sellUnit: 'kilo',
|
||||
category: 'کیک',
|
||||
image: img1040,
|
||||
options: [],
|
||||
},
|
||||
]
|
||||
|
||||
const sellUnitLabel: Record<SellUnit, string> = {
|
||||
unit: 'واحد',
|
||||
kilo: 'کیلو',
|
||||
}
|
||||
|
||||
export function formatPriceParts(product: Product): {
|
||||
amount: string
|
||||
label: string
|
||||
} {
|
||||
return {
|
||||
amount: product.price.toLocaleString('fa-IR'),
|
||||
label: `تومان - ${sellUnitLabel[product.sellUnit]}`,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
export type UserRole = 'customer' | 'admin' | 'superAdmin'
|
||||
|
||||
export type UserCategory = 'پزشک' | 'کسبه' | 'مهندس'
|
||||
|
||||
export type UserTitle =
|
||||
| 'سرکار خانم'
|
||||
| 'جناب آقای'
|
||||
| 'جناب دکتر'
|
||||
| 'خانم دکتر'
|
||||
| 'جناب آقای مهندس'
|
||||
| 'سرکار خانم مهندس'
|
||||
|
||||
export type User = {
|
||||
id: string
|
||||
title: UserTitle
|
||||
firstName: string
|
||||
lastName: string
|
||||
category: UserCategory | null
|
||||
cellNumber: string
|
||||
totalOrders: number
|
||||
totalTransaction: number
|
||||
role: UserRole
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export const userCategories: UserCategory[] = ['پزشک', 'کسبه', 'مهندس']
|
||||
|
||||
export const userTitles: UserTitle[] = [
|
||||
'سرکار خانم',
|
||||
'جناب آقای',
|
||||
'جناب دکتر',
|
||||
'خانم دکتر',
|
||||
'جناب آقای مهندس',
|
||||
'سرکار خانم مهندس',
|
||||
]
|
||||
|
||||
export const userRoles: { id: UserRole; label: string }[] = [
|
||||
{ id: 'customer', label: 'مشتری' },
|
||||
{ id: 'admin', label: 'ادمین' },
|
||||
{ id: 'superAdmin', label: 'سوپر ادمین' },
|
||||
]
|
||||
|
||||
export const userRoleLabel: Record<UserRole, string> = {
|
||||
customer: 'مشتری',
|
||||
admin: 'ادمین',
|
||||
superAdmin: 'سوپر ادمین',
|
||||
}
|
||||
|
||||
export function isElevatedRole(role: UserRole) {
|
||||
return role === 'admin' || role === 'superAdmin'
|
||||
}
|
||||
|
||||
export function createUser(input: {
|
||||
title: UserTitle
|
||||
firstName: string
|
||||
lastName: string
|
||||
category: UserCategory | null
|
||||
cellNumber: string
|
||||
}): User {
|
||||
return {
|
||||
id: `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||
title: input.title,
|
||||
firstName: input.firstName,
|
||||
lastName: input.lastName,
|
||||
category: input.category,
|
||||
cellNumber: input.cellNumber,
|
||||
totalOrders: 0,
|
||||
totalTransaction: 0,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
export const users: User[] = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'سرکار خانم',
|
||||
firstName: 'سارا',
|
||||
lastName: 'محمدی',
|
||||
category: 'پزشک',
|
||||
cellNumber: '09121234567',
|
||||
totalOrders: 24,
|
||||
totalTransaction: 18500000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'علی',
|
||||
lastName: 'رضایی',
|
||||
category: 'کسبه',
|
||||
cellNumber: '09131234567',
|
||||
totalOrders: 8,
|
||||
totalTransaction: 4200000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'خانم دکتر',
|
||||
firstName: 'مریم',
|
||||
lastName: 'حسینی',
|
||||
category: 'پزشک',
|
||||
cellNumber: '09191234567',
|
||||
totalOrders: 56,
|
||||
totalTransaction: 48200000,
|
||||
role: 'admin',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: 'جناب آقای مهندس',
|
||||
firstName: 'رضا',
|
||||
lastName: 'کریمی',
|
||||
category: 'مهندس',
|
||||
cellNumber: '09351234567',
|
||||
totalOrders: 112,
|
||||
totalTransaction: 128500000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: 'سرکار خانم',
|
||||
firstName: 'نازنین',
|
||||
lastName: 'احمدی',
|
||||
category: null,
|
||||
cellNumber: '09125551234',
|
||||
totalOrders: 3,
|
||||
totalTransaction: 950000,
|
||||
role: 'customer',
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: 'جناب دکتر',
|
||||
firstName: 'امیر',
|
||||
lastName: 'نوری',
|
||||
category: 'پزشک',
|
||||
cellNumber: '09187654321',
|
||||
totalOrders: 41,
|
||||
totalTransaction: 27600000,
|
||||
role: 'superAdmin',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
title: 'سرکار خانم مهندس',
|
||||
firstName: 'الهام',
|
||||
lastName: 'صادقی',
|
||||
category: 'مهندس',
|
||||
cellNumber: '09012345678',
|
||||
totalOrders: 19,
|
||||
totalTransaction: 9800000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'حسین',
|
||||
lastName: 'موسوی',
|
||||
category: 'کسبه',
|
||||
cellNumber: '09123334455',
|
||||
totalOrders: 1,
|
||||
totalTransaction: 185000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'فاطمه',
|
||||
lastName: 'کاظمی',
|
||||
category: 'کسبه',
|
||||
cellNumber: '09361112233',
|
||||
totalOrders: 67,
|
||||
totalTransaction: 74500000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'مهدی',
|
||||
lastName: 'جعفری',
|
||||
category: null,
|
||||
cellNumber: '09146667788',
|
||||
totalOrders: 12,
|
||||
totalTransaction: 5600000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '11',
|
||||
title: 'سرکار خانم',
|
||||
firstName: 'زهرا',
|
||||
lastName: 'امینی',
|
||||
category: 'پزشک',
|
||||
cellNumber: '09129998877',
|
||||
totalOrders: 33,
|
||||
totalTransaction: 21400000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '12',
|
||||
title: 'جناب آقای مهندس',
|
||||
firstName: 'پویا',
|
||||
lastName: 'شریفی',
|
||||
category: 'مهندس',
|
||||
cellNumber: '09170001122',
|
||||
totalOrders: 5,
|
||||
totalTransaction: 2100000,
|
||||
role: 'admin',
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: '13',
|
||||
title: 'سرکار خانم',
|
||||
firstName: 'نگار',
|
||||
lastName: 'طاهری',
|
||||
category: 'کسبه',
|
||||
cellNumber: '09354445566',
|
||||
totalOrders: 9,
|
||||
totalTransaction: 3700000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '14',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'کیان',
|
||||
lastName: 'باقری',
|
||||
category: 'کسبه',
|
||||
cellNumber: '09183332211',
|
||||
totalOrders: 88,
|
||||
totalTransaction: 96500000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '15',
|
||||
title: 'خانم دکتر',
|
||||
firstName: 'آیدا',
|
||||
lastName: 'قاسمی',
|
||||
category: 'پزشک',
|
||||
cellNumber: '09125556677',
|
||||
totalOrders: 15,
|
||||
totalTransaction: 8200000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '16',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'بهراد',
|
||||
lastName: 'اکبری',
|
||||
category: null,
|
||||
cellNumber: '09014445566',
|
||||
totalOrders: 2,
|
||||
totalTransaction: 640000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '17',
|
||||
title: 'سرکار خانم مهندس',
|
||||
firstName: 'مینا',
|
||||
lastName: 'رحیمی',
|
||||
category: 'مهندس',
|
||||
cellNumber: '09196665544',
|
||||
totalOrders: 29,
|
||||
totalTransaction: 15800000,
|
||||
role: 'admin',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '18',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'سامان',
|
||||
lastName: 'نجفی',
|
||||
category: 'کسبه',
|
||||
cellNumber: '09357778899',
|
||||
totalOrders: 6,
|
||||
totalTransaction: 2450000,
|
||||
role: 'customer',
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: '19',
|
||||
title: 'سرکار خانم',
|
||||
firstName: 'پریسا',
|
||||
lastName: 'حیدری',
|
||||
category: 'پزشک',
|
||||
cellNumber: '09121112233',
|
||||
totalOrders: 47,
|
||||
totalTransaction: 33200000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
title: 'جناب آقای مهندس',
|
||||
firstName: 'آرمان',
|
||||
lastName: 'فرهادی',
|
||||
category: 'مهندس',
|
||||
cellNumber: '09188889900',
|
||||
totalOrders: 73,
|
||||
totalTransaction: 81200000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '21',
|
||||
title: 'سرکار خانم',
|
||||
firstName: 'لیلا',
|
||||
lastName: 'صالحی',
|
||||
category: null,
|
||||
cellNumber: '09350001122',
|
||||
totalOrders: 4,
|
||||
totalTransaction: 1180000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '22',
|
||||
title: 'جناب دکتر',
|
||||
firstName: 'نیما',
|
||||
lastName: 'یوسفی',
|
||||
category: 'پزشک',
|
||||
cellNumber: '09134445566',
|
||||
totalOrders: 18,
|
||||
totalTransaction: 9700000,
|
||||
role: 'superAdmin',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '23',
|
||||
title: 'سرکار خانم',
|
||||
firstName: 'هدیه',
|
||||
lastName: 'مرادی',
|
||||
category: 'کسبه',
|
||||
cellNumber: '09127778899',
|
||||
totalOrders: 11,
|
||||
totalTransaction: 4900000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
id: '24',
|
||||
title: 'جناب آقای',
|
||||
firstName: 'سینا',
|
||||
lastName: 'پناهی',
|
||||
category: 'مهندس',
|
||||
cellNumber: '09016667788',
|
||||
totalOrders: 22,
|
||||
totalTransaction: 14600000,
|
||||
role: 'customer',
|
||||
disabled: false,
|
||||
},
|
||||
]
|
||||
|
||||
export function formatCellNumber(value: string) {
|
||||
return value.replace(/\D/g, '')
|
||||
}
|
||||
Reference in New Issue
Block a user