Add customer SMS/Excel tools, selection bar, and sticky import toasts.
Bulk and single SMS from Users, row selection with overflow summary, persistent large import toasts, and business SMS sender in Super Admin. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
2a32c46b2e
commit
4c3bf8324e
@@ -1,4 +1,4 @@
|
||||
import { apiRequest } from '../lib/api'
|
||||
import { apiRequest, apiRequestBlob, apiRequestForm } from '../lib/api'
|
||||
import { getActiveBusinessId } from '../lib/businessContext'
|
||||
|
||||
export interface BusinessCustomer {
|
||||
@@ -131,3 +131,84 @@ export async function searchCustomers(
|
||||
{ auth: true, signal },
|
||||
)
|
||||
}
|
||||
|
||||
export async function downloadCustomersExcel() {
|
||||
const { blob } = await apiRequestBlob(businessPath('/export'), { auth: true })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = customersExcelFilename()
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
link.remove()
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
function customersExcelFilename(now = new Date()) {
|
||||
const parts = new Intl.DateTimeFormat('en-GB', {
|
||||
timeZone: 'Asia/Tehran',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hourCycle: 'h23',
|
||||
}).formatToParts(now)
|
||||
|
||||
const pick = (type: Intl.DateTimeFormatPartTypes) =>
|
||||
parts.find((part) => part.type === type)?.value ?? ''
|
||||
|
||||
return `customers - ${pick('year')}-${pick('month')}-${pick('day')} - ${pick('hour')}-${pick('minute')}.xlsx`
|
||||
}
|
||||
|
||||
export interface CustomersExcelImportResult {
|
||||
message: string
|
||||
total: number
|
||||
created: number
|
||||
linked: number
|
||||
skipped: number
|
||||
skipSamples: string[]
|
||||
}
|
||||
|
||||
export async function importCustomersExcel(file: File) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return apiRequestForm<CustomersExcelImportResult>(businessPath('/import'), formData, {
|
||||
auth: true,
|
||||
})
|
||||
}
|
||||
|
||||
export interface SendCustomerSmsResult {
|
||||
enabled: boolean
|
||||
message: string
|
||||
serverId?: string
|
||||
source?: string
|
||||
}
|
||||
|
||||
export interface SendCustomersBulkSmsResult {
|
||||
enabled: boolean
|
||||
message: string
|
||||
recipientCount: number
|
||||
serverIds?: string[]
|
||||
source?: string
|
||||
}
|
||||
|
||||
export async function sendCustomerSms(userId: string, message: string) {
|
||||
return apiRequest<SendCustomerSmsResult>(businessPath(`/${userId}/sms`), {
|
||||
method: 'POST',
|
||||
auth: true,
|
||||
body: { message },
|
||||
})
|
||||
}
|
||||
|
||||
/** Bulk SMS via Gama SendBulk. Omit userIds (or pass []) to send to all enabled customers. */
|
||||
export async function sendCustomersBulkSms(message: string, userIds?: string[]) {
|
||||
return apiRequest<SendCustomersBulkSmsResult>(businessPath('/sms'), {
|
||||
method: 'POST',
|
||||
auth: true,
|
||||
body: {
|
||||
message,
|
||||
...(userIds && userIds.length > 0 ? { userIds } : {}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user