Initial commit: Meshkee dashboards monorepo.

Includes business, customer, and super-admin apps with shared packages and production deploy scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-07-22 13:48:53 +03:30
co-authored by Cursor
commit f566387c61
509 changed files with 62690 additions and 0 deletions
+217
View File
@@ -0,0 +1,217 @@
import { useEffect, useState } from 'react'
import { Plus } from 'lucide-react'
import { useToast } from '../context/ToastContext'
import { BrandModal } from '../components/BrandModal'
import { BrandRow } from '../components/BrandRow'
import { Breadcrumbs } from '../components/Breadcrumbs'
import { ConfirmDeleteModal } from '../components/ConfirmDeleteModal'
import type { Brand, BrandFormData } from '../types/brand'
import { ApiError } from '../lib/api'
import { resolveDataUrlToMediaId } from '../services/mediaService'
import {
createBrand,
deleteBrand,
listAllBrands,
mapBrandApiToUi,
toBrandFormPayload,
updateBrand,
} from '../services/brandService'
import pageStyles from '../components/PageContent.module.css'
import styles from './BrandsPage.module.css'
export function BrandsPage() {
const { showToast } = useToast()
const [brands, setBrands] = useState<Brand[]>([])
const [modalOpen, setModalOpen] = useState(false)
const [modalTitle, setModalTitle] = useState('Add Brand')
const [editingBrand, setEditingBrand] = useState<Brand | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [isSubmitting, setIsSubmitting] = useState(false)
const [error, setError] = useState('')
const [deleteTarget, setDeleteTarget] = useState<Brand | null>(null)
useEffect(() => {
const controller = new AbortController()
void loadBrands(controller.signal)
return () => controller.abort()
}, [])
async function loadBrands(signal?: AbortSignal) {
setIsLoading(true)
setError('')
try {
const items = await listAllBrands(signal)
setBrands(items.map(mapBrandApiToUi))
} catch (err) {
if (err instanceof DOMException && err.name === 'AbortError') return
if (err instanceof ApiError) {
setError(err.message)
} else {
setError('Unable to load brands.')
}
} finally {
setIsLoading(false)
}
}
function openCreateModal() {
setEditingBrand(null)
setModalTitle('Add Brand')
setModalOpen(true)
}
function openEditModal(brand: Brand) {
setEditingBrand(brand)
setModalTitle('Edit Brand')
setModalOpen(true)
}
async function handleSubmit(data: BrandFormData) {
setIsSubmitting(true)
setError('')
try {
const resolvedImageMediaId = await resolveDataUrlToMediaId(
data.image,
'brand-logo.png',
data.imageMediaId,
)
if (editingBrand) {
const result = await updateBrand(editingBrand.id, {
...toBrandFormPayload(data),
imageMediaId: resolvedImageMediaId,
})
setBrands((prev) =>
prev.map((brand) =>
brand.id === editingBrand.id ? mapBrandApiToUi(result.brand) : brand,
),
)
showToast('Brand updated.', 'success')
} else {
const result = await createBrand(toBrandFormPayload(data, resolvedImageMediaId))
setBrands((prev) => [...prev, mapBrandApiToUi(result.brand)])
showToast('Brand created.', 'success')
}
setModalOpen(false)
setEditingBrand(null)
} catch (err) {
if (err instanceof ApiError) {
setError(err.message)
} else {
setError('Unable to save brand.')
}
} finally {
setIsSubmitting(false)
}
}
async function confirmDelete() {
if (!deleteTarget) return
setIsSubmitting(true)
setError('')
try {
await deleteBrand(deleteTarget.id)
setBrands((prev) => prev.filter((brand) => brand.id !== deleteTarget.id))
setDeleteTarget(null)
showToast('Brand deleted.', 'success')
} catch (err) {
if (err instanceof ApiError) {
setError(err.message)
} else {
setError('Unable to delete brand.')
}
} finally {
setIsSubmitting(false)
}
}
return (
<main className={pageStyles.content}>
<Breadcrumbs
items={[
{ label: 'Dashboard', href: '/' },
{ label: 'Products', href: '/products' },
{ label: 'Brands' },
]}
/>
<div className={pageStyles.pageHeader}>
<div>
<h2 className={pageStyles.pageTitle}>Brands</h2>
<p className={pageStyles.pageSubtitle}>
Manage product brands for your store catalog.
</p>
</div>
</div>
{error && (
<div className={styles.error} role="alert">
{error}
</div>
)}
<div className={styles.list}>
{isLoading ? (
<p className={styles.empty}>Loading brands...</p>
) : brands.length === 0 ? (
<p className={styles.empty}>No brands yet. Click + to add one.</p>
) : (
brands.map((brand) => (
<BrandRow
key={brand.id}
brand={brand}
onEdit={(id) => {
const item = brands.find((entry) => entry.id === id)
if (item) openEditModal(item)
}}
onRemove={(id) => {
const item = brands.find((entry) => entry.id === id)
if (item) setDeleteTarget(item)
}}
/>
))
)}
</div>
<BrandModal
open={modalOpen}
onClose={() => {
if (!isSubmitting) {
setModalOpen(false)
setEditingBrand(null)
}
}}
onSubmit={handleSubmit}
editingBrand={editingBrand}
title={modalTitle}
isSubmitting={isSubmitting}
/>
<ConfirmDeleteModal
open={!!deleteTarget}
title="Delete Brand"
message={
deleteTarget
? `Are you sure you want to delete "${deleteTarget.nameEn}"? Products linked to this brand will have their brand cleared.`
: ''
}
onConfirm={confirmDelete}
onCancel={() => !isSubmitting && setDeleteTarget(null)}
/>
<div className={styles.fabDock}>
<button
type="button"
className={styles.addFab}
onClick={openCreateModal}
aria-label="Add brand"
>
<Plus size={24} />
</button>
</div>
</main>
)
}