add template managment
This commit is contained in:
@@ -4,10 +4,14 @@ import styles from '@/app/styles/module/login.module.scss'
|
||||
import { useActionState, useState, useEffect } from 'react';
|
||||
import { createStuff } from '@/app/actions/stuffActions';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { IconEye } from '@/app/ui/icons/icons';
|
||||
import { IconEye, IconDiscet, IconDelete } from '@/app/ui/icons/icons';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
import { useStuffTemplates } from '@/app/hooks/react-query/stuff/useStuffTemplates';
|
||||
import DropDownList from '@/app/components/dropDownList';
|
||||
import { createStuffTemplates, removeStuffTemplates } from '@/app/actions/stuffActions';
|
||||
import ModalWindow from '@/app/components/modalWindow';
|
||||
|
||||
const createStuffSchema = z.object({
|
||||
fullName: z.string()
|
||||
@@ -61,6 +65,7 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
const t = useTranslations('Login-register-form');
|
||||
const tGeneral = useTranslations('Global');
|
||||
const tPermissions = useTranslations('Permissions');
|
||||
const { data: templates, refetch: refetchTemplates } = useStuffTemplates();
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [changePassword, setChangePassword] = useState(true);
|
||||
@@ -80,6 +85,13 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
tariffs: 0,
|
||||
});
|
||||
|
||||
const [selectedTemplateId, setSelectedTemplateId] = useState<string>('');
|
||||
const [isSavingTemplate, setIsSavingTemplate] = useState(false);
|
||||
const [newTemplateName, setNewTemplateName] = useState('');
|
||||
const [showSaveDialog, setShowSaveDialog] = useState(false);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [templateToDelete, setTemplateToDelete] = useState<number | null>(null);
|
||||
|
||||
const permissionsConfig = [
|
||||
{ key: 'subscriptions', label: tPermissions('subscriptions'), description: tPermissions('subscriptions-desc') },
|
||||
{ key: 'mailings', label: tPermissions('mailings'), description: tPermissions('mailings-desc') },
|
||||
@@ -101,6 +113,10 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
...prev,
|
||||
[key]: value
|
||||
}));
|
||||
|
||||
if (selectedTemplateId) {
|
||||
setSelectedTemplateId('');
|
||||
}
|
||||
};
|
||||
|
||||
function toggleShowPassword() {
|
||||
@@ -109,6 +125,66 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const applyTemplate = (templateId: string) => {
|
||||
if (!templates) return;
|
||||
|
||||
const template = templates.find(t => t.id.toString() === templateId);
|
||||
if (template) {
|
||||
setPermissions(template.permissions);
|
||||
setSelectedTemplateId(templateId);
|
||||
toast.success(`${tGeneral('template-applied')}: ${template.name}`);
|
||||
}
|
||||
};
|
||||
|
||||
const saveCurrentAsTemplate = async () => {
|
||||
if (!newTemplateName.trim()) {
|
||||
toast.error(tGeneral('template-name-required'));
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSavingTemplate(true);
|
||||
try {
|
||||
const result = await createStuffTemplates(newTemplateName, changePassword, permissions);
|
||||
if (result) {
|
||||
toast.success(`${tGeneral('template-saved-successfully')}: ${newTemplateName}`);
|
||||
setNewTemplateName('');
|
||||
setShowSaveDialog(false);
|
||||
await refetchTemplates();
|
||||
|
||||
if (result.id) {
|
||||
setSelectedTemplateId(result.id.toString());
|
||||
}
|
||||
} else {
|
||||
toast.error(tGeneral('template-save-failed'));
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(tGeneral('template-save-failed'));
|
||||
} finally {
|
||||
setIsSavingTemplate(false);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteTemplate = async () => {
|
||||
if (!templateToDelete) return;
|
||||
|
||||
try {
|
||||
const result = await removeStuffTemplates(templateToDelete);
|
||||
if (result) {
|
||||
toast.success(tGeneral('template-deleted-successfully'));
|
||||
await refetchTemplates();
|
||||
if (selectedTemplateId === templateToDelete.toString()) {
|
||||
setSelectedTemplateId('');
|
||||
}
|
||||
setShowDeleteConfirm(false);
|
||||
setTemplateToDelete(null);
|
||||
} else {
|
||||
toast.error(tGeneral('template-delete-failed'));
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(tGeneral('template-delete-failed'));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (state?.success) {
|
||||
toast.success(tGeneral('staff-created-successfully'));
|
||||
@@ -123,9 +199,7 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
}, [state, queryClient, onSuccess, t, tGeneral]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="create-staff-window"
|
||||
>
|
||||
<div className="create-staff-window">
|
||||
<form
|
||||
className={`${styles['']}`}
|
||||
action={formAction}
|
||||
@@ -224,6 +298,62 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
{tGeneral('permissions')}
|
||||
</h3>
|
||||
|
||||
<div className="templates-section">
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
|
||||
<h3 style={{ margin: 0 }}>{tGeneral('template-management')}</h3>
|
||||
<div style={{ display: 'flex', gap: '8px' }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowSaveDialog(true)}
|
||||
className="btn-icon"
|
||||
title={tGeneral('save-current-as-template')}
|
||||
disabled={isPending}
|
||||
>
|
||||
<IconDiscet />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<DropDownList
|
||||
value={selectedTemplateId}
|
||||
callBack={applyTemplate}
|
||||
translatedValue={
|
||||
selectedTemplateId && templates
|
||||
? templates.find(t => t.id.toString() === selectedTemplateId)?.name
|
||||
: tGeneral('select-template')
|
||||
}
|
||||
>
|
||||
<option value="">{tGeneral('select-template')}</option>
|
||||
{templates?.map((template) => (
|
||||
<option key={template.id} value={template.id.toString()}>
|
||||
{template.name}
|
||||
</option>
|
||||
))}
|
||||
</DropDownList>
|
||||
</div>
|
||||
|
||||
{selectedTemplateId && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const template = templates?.find(t => t.id.toString() === selectedTemplateId);
|
||||
if (template) {
|
||||
setTemplateToDelete(template.id);
|
||||
setShowDeleteConfirm(true);
|
||||
}
|
||||
}}
|
||||
className="btn-icon btn-danger"
|
||||
title={tGeneral('delete-template')}
|
||||
disabled={isPending}
|
||||
>
|
||||
<IconDelete />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="permissions-list">
|
||||
{permissionsConfig.map((perm) => {
|
||||
const currentValue = permissions[perm.key as keyof typeof permissions];
|
||||
@@ -233,7 +363,7 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
<div className="permission-header">
|
||||
<div className="permission-info">
|
||||
<h4 className="permission-title">{perm.label}</h4>
|
||||
<p className="permission-description">{perm.description}</p>
|
||||
{/* <p className="permission-description">{perm.description}</p> */}
|
||||
</div>
|
||||
<div className="permission-controls">
|
||||
<div className="permission-level-buttons">
|
||||
@@ -295,6 +425,51 @@ export function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
|
||||
)}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<ModalWindow state={showSaveDialog} callBack={setShowSaveDialog}>
|
||||
<div
|
||||
className="min-w-100"
|
||||
>
|
||||
<h3>{tGeneral('save-template')}</h3>
|
||||
<input
|
||||
type="text"
|
||||
value={newTemplateName}
|
||||
onChange={(e) => setNewTemplateName(e.target.value)}
|
||||
placeholder={tGeneral('enter-template-name')}
|
||||
className="template-name-input"
|
||||
autoFocus
|
||||
/>
|
||||
<div className="modal-buttons">
|
||||
<button onClick={() => setShowSaveDialog(false)} className="btn btn-secondary">
|
||||
{tGeneral('cancel')}
|
||||
</button>
|
||||
<button onClick={saveCurrentAsTemplate} disabled={isSavingTemplate} className="btn btn-primary">
|
||||
{isSavingTemplate ? tGeneral('saving') : tGeneral('save')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWindow>
|
||||
|
||||
<ModalWindow state={showDeleteConfirm} callBack={setShowDeleteConfirm}>
|
||||
<h3
|
||||
className="mb-4"
|
||||
>
|
||||
{tGeneral('delete-template-confirm')}
|
||||
</h3>
|
||||
<p
|
||||
className="mb-4"
|
||||
>
|
||||
{tGeneral('delete-template-warning')}
|
||||
</p>
|
||||
<div className="modal-buttons">
|
||||
<button onClick={() => setShowDeleteConfirm(false)} className="btn btn-secondary">
|
||||
{tGeneral('cancel')}
|
||||
</button>
|
||||
<button onClick={deleteTemplate} className="btn btn-danger">
|
||||
{tGeneral('delete')}
|
||||
</button>
|
||||
</div>
|
||||
</ModalWindow>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user