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
+167
View File
@@ -0,0 +1,167 @@
import { getAccessToken, clearTokens, setTokens } from '../lib/api'
import { getActiveBusinessId } from '../lib/businessContext'
import { API_BASE_URL } from '../lib/config'
import { ensureJpegUploadFile, ensureUploadFile } from '../utils/imageUpload'
export interface MediaItem {
id: string
publicUrl: string
fileName: string
originalFileName: string
mimeType: string
width: number | null
height: number | null
}
function isDataUrl(value: string) {
return value.startsWith('data:')
}
function businessPath(suffix = '') {
const businessId = getActiveBusinessId()
if (!businessId) {
throw new Error('No active business selected. Please sign in again.')
}
return `/businesses/${businessId}/media${suffix}`
}
async function refreshAccessToken() {
const refreshToken = localStorage.getItem('meshkee_business_refresh_token')
if (!refreshToken) return false
const response = await fetch(`${API_BASE_URL}/auth/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken }),
})
if (!response.ok) {
clearTokens()
return false
}
const data = await response.json()
setTokens(data.accessToken, data.refreshToken)
return true
}
function parseUploadError(payload: unknown, status: number) {
if (payload && typeof payload === 'object') {
const message = (payload as { message?: string | string[] }).message
if (Array.isArray(message)) {
return message.join(', ')
}
if (typeof message === 'string' && message) {
return message
}
}
return `Upload failed with status ${status}`
}
export async function uploadMediaFiles(
files: File[],
signal?: AbortSignal,
): Promise<MediaItem[]> {
if (!files.length) return []
const send = async () => {
const formData = new FormData()
files.forEach((file) => formData.append('files', file))
const headers = new Headers()
const accessToken = getAccessToken()
if (accessToken) {
headers.set('Authorization', `Bearer ${accessToken}`)
}
return fetch(`${API_BASE_URL}${businessPath()}`, {
method: 'POST',
headers,
body: formData,
signal,
})
}
let response = await send()
if (response.status === 401) {
const refreshed = await refreshAccessToken()
if (refreshed) {
response = await send()
}
}
const payload = await response.json().catch(() => null)
if (!response.ok) {
throw new Error(parseUploadError(payload, response.status))
}
return (payload.items as Array<Record<string, unknown>>).map((item) => ({
id: String(item.id),
publicUrl: String(item.publicUrl),
fileName: String(item.fileName),
originalFileName: String(item.originalFileName),
mimeType: String(item.mimeType),
width: typeof item.width === 'number' ? item.width : null,
height: typeof item.height === 'number' ? item.height : null,
}))
}
export async function resolveDataUrlToMediaId(
value: string | null,
filename: string,
existingMediaId?: string | null,
): Promise<string | null> {
if (!value) return null
if (!isDataUrl(value)) {
return existingMediaId ?? null
}
const file = filename.toLowerCase().endsWith('.png')
? await ensureUploadFile(value, filename)
: await ensureJpegUploadFile(value, filename)
const uploaded = await uploadMediaFiles([file])
return uploaded[0]?.id ?? null
}
export async function resolveHtmlEmbeddedDataUrls(html: string): Promise<string> {
if (!html.includes('data:')) return html
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
const images = Array.from(doc.querySelectorAll('img'))
for (let index = 0; index < images.length; index += 1) {
const src = images[index].getAttribute('src')
if (!src || !isDataUrl(src)) continue
const file = await ensureJpegUploadFile(src, `inline-image-${index + 1}.jpg`)
const uploaded = await uploadMediaFiles([file])
if (uploaded[0]) {
images[index].setAttribute('src', uploaded[0].publicUrl)
}
}
return doc.body.innerHTML
}
export async function resolveDataUrlsToMediaIds(
values: string[],
existingMediaIds: string[],
): Promise<string[]> {
const resolved: string[] = []
for (let index = 0; index < values.length; index += 1) {
const value = values[index]
if (isDataUrl(value)) {
const file = await ensureJpegUploadFile(value, `product-image-${index + 1}.jpg`)
const uploaded = await uploadMediaFiles([file])
if (uploaded[0]) resolved.push(uploaded[0].id)
} else if (existingMediaIds[index]) {
resolved.push(existingMediaIds[index])
}
}
return resolved
}