notification perfer

This commit is contained in:
hamid zarghami
2025-12-22 09:10:09 +03:30
parent bc91153231
commit 4a6fb229d8
7 changed files with 95 additions and 43 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
VITE_TOKEN_NAME = 'dmnu_a_t'
VITE_REFRESH_TOKEN_NAME = 'dmnu-a-rt'
VITE_BASE_URL = 'https://dmenuplus-api.dev.danakcorp.com'
# VITE_BASE_URL = 'http://192.168.99.242:4000'
# VITE_BASE_URL = 'https://dmenuplus-api.dev.danakcorp.com'
VITE_BASE_URL = 'http://192.168.99.242:4000'
VITE_SOCKET_URL = 'https://dmenuplus-api.dev.danakcorp.com'
@@ -1,9 +1,8 @@
import { type FC, useState, useEffect } from 'react'
import DefaulModal from '@/components/DefaulModal'
import Select from '@/components/Select'
import Button from '@/components/Button'
import { Checkbox } from '@/components/ui/checkbox'
import { useUpdateNotification } from '../hooks/useNotificationData'
import { NotificationType } from '../enum/Enum'
import type { Notification } from '../types/Types'
interface Props {
@@ -12,29 +11,50 @@ interface Props {
notification: Notification | null
}
type ChannelType = "sms" | "push" | "in-app"
const channelOptions: { value: ChannelType; label: string }[] = [
{ value: "sms", label: 'پیامک' },
{ value: "push", label: 'پوش' },
{ value: "in-app", label: 'درون برنامه' },
]
const getTitleLabel = (title: string): string => {
const titleMap: Record<string, string> = {
'order.created': 'سفارش ایجاد شد',
'order.status.changed': 'تغییر وضعیت سفارش',
'pager.created': 'پیجر ایجاد شد',
'payment.success': 'پرداخت موفق',
'review.created': 'نظر ایجاد شد',
}
return titleMap[title] || title
}
const EditNotificationTypeModal: FC<Props> = ({ open, close, notification }) => {
const [selectedType, setSelectedType] = useState<NotificationType>(NotificationType.NONE)
const [selectedChannels, setSelectedChannels] = useState<ChannelType[]>([])
const { mutate: updateNotification, isPending } = useUpdateNotification()
useEffect(() => {
if (notification) {
setSelectedType(notification.notificationType as NotificationType)
setSelectedChannels([...notification.channels])
}
}, [notification])
if (!notification) return null
const notificationTypeOptions = [
{ value: NotificationType.SMS, label: 'پیامک' },
{ value: NotificationType.PUSH, label: 'پوش' },
{ value: NotificationType.Both, label: 'هر دو' },
]
const handleToggleChannel = (channel: ChannelType, checked: boolean) => {
if (checked) {
setSelectedChannels((prev) => [...prev, channel])
} else {
setSelectedChannels((prev) => prev.filter((c) => c !== channel))
}
}
const handleSubmit = () => {
updateNotification(
{
id: notification.id,
notificationType: selectedType,
channels: selectedChannels,
},
{
onSuccess: () => {
@@ -58,17 +78,29 @@ const EditNotificationTypeModal: FC<Props> = ({ open, close, notification }) =>
عنوان
</label>
<p className="text-sm font-medium">
{notification.title || '-'}
{notification.title ? getTitleLabel(notification.title) : '-'}
</p>
</div>
<div>
<Select
label="نوع اعلان"
items={notificationTypeOptions}
value={selectedType}
onChange={(e) => setSelectedType(e.target.value as NotificationType)}
<label className="text-sm mb-3 block">
کانالهای اعلان
</label>
<div className="space-y-3">
{channelOptions.map((option) => (
<div key={option.value} className="flex items-center gap-2">
<Checkbox
checked={selectedChannels.includes(option.value)}
onCheckedChange={(checked) =>
handleToggleChannel(option.value, checked as boolean)
}
/>
<label className="text-sm cursor-pointer">
{option.label}
</label>
</div>
))}
</div>
</div>
<div className="flex justify-end gap-3 mt-6 border-t border-gray-200 pt-4">
@@ -4,13 +4,33 @@ import type { Notification } from '../types/Types'
import { formatOptionalDate } from '@/helpers/func'
import Status from '@/components/Status'
const getNotificationTypeVariant = (type: string): 'success' | 'error' | 'warning' | 'info' | 'pending' => {
const getChannelVariant = (channel: string): 'success' | 'error' | 'warning' | 'info' | 'pending' => {
const variantMap: Record<string, 'success' | 'error' | 'warning' | 'info' | 'pending'> = {
'sms': 'info',
'push': 'warning',
'both': 'success',
'in-app': 'success',
}
return variantMap[type] || 'info'
return variantMap[channel] || 'info'
}
const getChannelLabel = (channel: string): string => {
const labels: Record<string, string> = {
'sms': 'پیامک',
'push': 'پوش',
'in-app': 'درون برنامه',
}
return labels[channel] || channel
}
const getTitleLabel = (title: string): string => {
const titleMap: Record<string, string> = {
'order.created': 'سفارش ایجاد شد',
'order.status.changed': 'تغییر وضعیت سفارش',
'pager.created': 'پیجر ایجاد شد',
'payment.success': 'پرداخت موفق',
'review.created': 'نظر ایجاد شد',
}
return titleMap[title] || title
}
type Props = {
@@ -25,25 +45,28 @@ export const getNotificationTableColumns = ({ onEdit }: Props): ColumnType<Notif
render: (item: Notification) => {
return (
<div className="max-w-xs truncate" title={item.title}>
{item.title || '-'}
{item.title ? getTitleLabel(item.title) : '-'}
</div>
)
}
},
{
key: 'notificationType',
title: 'نوع اعلان',
key: 'channels',
title: 'کانال‌های اعلان',
render: (item: Notification) => {
const typeLabels: Record<string, string> = {
'sms': 'پیامک',
'push': 'پوش',
'both': 'هر دو',
if (!item.channels || item.channels.length === 0) {
return <span className="text-gray-400">-</span>
}
return (
<div className="flex flex-wrap gap-2">
{item.channels.map((channel, index) => (
<Status
variant={getNotificationTypeVariant(item.notificationType)}
label={typeLabels[item.notificationType] || item.notificationType}
key={index}
variant={getChannelVariant(channel)}
label={getChannelLabel(channel)}
/>
))}
</div>
)
}
},
+1 -2
View File
@@ -1,6 +1,5 @@
export const enum NotificationType {
NONE = "none",
IN_APP = "in-app",
SMS = "sms",
PUSH = "push",
Both = "both",
}
@@ -1,4 +1,3 @@
import type { NotificationType } from "../enum/Enum";
import * as api from "../service/NotificationService";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
@@ -16,11 +15,11 @@ export const useUpdateNotification = () => {
return useMutation({
mutationFn: ({
id,
notificationType,
channels,
}: {
id: string;
notificationType: NotificationType;
}) => api.updateNotification(id, notificationType),
channels: ("sms" | "push" | "in-app")[];
}) => api.updateNotification(id, channels),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["notifications"] });
},
@@ -1,6 +1,5 @@
import axios from "@/config/axios";
import type { GetNotificationsResponse } from "../types/Types";
import type { NotificationType } from "../enum/Enum";
export const getNotifications = async (
params?: Record<string, string | number>
@@ -14,10 +13,10 @@ export const getNotifications = async (
export const updateNotification = async (
id: string,
notificationType: NotificationType
channels: ("sms" | "push" | "in-app")[]
) => {
const { data } = await axios.patch(`/admin/notification-preferences/${id}`, {
notificationType,
channels,
});
return data;
};
+1 -1
View File
@@ -8,7 +8,7 @@ export interface Notification extends RowDataType {
deletedAt: string | null;
restaurant: string;
title: string;
notificationType: "sms" | "push" | "both";
channels: ("sms" | "push" | "in-app")[];
}
export type GetNotificationsResponse = IResponse<Notification[]>;