- navigate(-1)}>Cancel
-
- {loading ? 'Creating...' : (
+ navigate('/admin/templates')}>Cancel
+
+ {loading ? 'Saving...' : (
<>
- Create Template
+ {isEditing ? 'Update Template' : 'Create Template'}
>
)}
diff --git a/src/pages/CreateAdminRequest/CreateAdminRequest.tsx b/src/pages/CreateAdminRequest/CreateAdminRequest.tsx
index 5ebe721..7800ae9 100644
--- a/src/pages/CreateAdminRequest/CreateAdminRequest.tsx
+++ b/src/pages/CreateAdminRequest/CreateAdminRequest.tsx
@@ -1,9 +1,10 @@
import { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
-import { ArrowLeft, Save, ChevronRight, Check } from 'lucide-react';
+import { ArrowLeft, ChevronRight, Check } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useAuth } from '@/contexts/AuthContext';
import { getTemplates, WorkflowTemplate as BackendTemplate } from '@/services/workflowTemplateApi';
+import { createWorkflowMultipart, submitWorkflow, CreateWorkflowFromFormPayload } from '@/services/workflowApi';
import { RequestTemplate } from '@/hooks/useCreateRequestForm';
import { FileText } from 'lucide-react';
import { AdminRequestDetailsStep } from './components/AdminRequestDetailsStep';
@@ -15,7 +16,7 @@ import { WizardStepper } from '@/components/workflow/CreateRequest/WizardStepper
export function CreateAdminRequest() {
const { templateId } = useParams<{ templateId: string }>();
const navigate = useNavigate();
- const { user } = useAuth();
+ const { user: _ } = useAuth(); // Keeping hook call but ignoring return if needed for auth check side effect, or just remove destructuring
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
@@ -63,7 +64,8 @@ export function CreateAdminRequest() {
});
} else {
toast.error('Template not found');
- navigate('/new-request');
+ // navigate('/new-request'); // Removed to prevent potential redirect loops
+ // We will show the "Template not found" UI below since template is null
}
} catch (error) {
console.error('Error loading template:', error);
@@ -84,13 +86,28 @@ export function CreateAdminRequest() {
try {
setSubmitting(true);
- // Construct the request payload
- // This matches the structure expected by the backend for a generic request
- // But we will likely need to adjust based on how "createRequest" is implemented globally
- // For now, we simulate the submission or call the common handler if available
+ const formPayload: CreateWorkflowFromFormPayload = {
+ templateId: template.id,
+ templateType: 'TEMPLATE',
+ title: formData.title,
+ description: formData.description,
+ priorityUi: template.priority === 'high' ? 'express' : 'standard',
+ approverCount: template.workflowApprovers?.length || 0,
+ approvers: (template.workflowApprovers || []).map((a: any) => ({
+ email: a.email,
+ name: a.name,
+ tat: a.tat,
+ tatType: 'hours'
+ })),
+ spectators: [],
+ ccList: []
+ };
- // Simulating API call for demonstration of flow
- await new Promise(resolve => setTimeout(resolve, 1500));
+ const response = await createWorkflowMultipart(formPayload, documents);
+
+ if (response && response.id) {
+ await submitWorkflow(response.id);
+ }
toast.success('Request Submitted Successfully', {
description: `Your request "${formData.title}" has been created.`
@@ -114,7 +131,29 @@ export function CreateAdminRequest() {
);
}
- if (!template) return null;
+ if (!template) {
+ return (
+
+
+
+
+
+
Template Not Found
+
+ The requested template could not be loaded. It may have been deleted or you do not have permission to view it.
+
+
+ navigate('/dashboard')}>
+ Go to Dashboard
+
+ navigate('/new-request')}>
+ Browse Templates
+
+
+
+
+ );
+ }
return (
diff --git a/src/pages/CreateRequest/CreateRequest.tsx b/src/pages/CreateRequest/CreateRequest.tsx
index 47968d2..fc932a3 100644
--- a/src/pages/CreateRequest/CreateRequest.tsx
+++ b/src/pages/CreateRequest/CreateRequest.tsx
@@ -13,7 +13,7 @@
* - components/ - UI components
*/
-import { useState, useRef, useEffect, useCallback } from 'react';
+import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
import { TemplateSelectionModal } from '@/components/modals/TemplateSelectionModal';
@@ -95,7 +95,7 @@ export function CreateRequest({
fetchTemplates();
}, []);
- const allTemplates = [...REQUEST_TEMPLATES, ...adminTemplates];
+ const allTemplates = useMemo(() => [...REQUEST_TEMPLATES, ...adminTemplates], [adminTemplates]);
// Form and state management hooks
const {
@@ -180,16 +180,30 @@ export function CreateRequest({
// - Steps 1, 3, or 4: Navigate back to previous screen (browser history)
// - Other steps: Go to previous step in wizard
const handleBackButton = useCallback(() => {
- if (currentStep === 1 || currentStep === 3 || currentStep === 4) {
- // On steps 1, 3, or 4, navigate back to previous screen using browser history
+ // If on the first step (Template Selection), always go back to dashboard
+ // This prevents infinite loops if the user was redirected here from an error page
+ if (currentStep === 1) {
+ navigate('/dashboard', { replace: true });
+ return;
+ }
+
+ // For other major steps (3=Approval, 4=Participants), we might want to go back to prev screen
+ // But for consistency and safety against loops, let's treat "Back" as "Previous Step"
+ // or explicit exit if at the start of a flow.
+
+ // Actually, keep the history logic ONLY for later steps if needed, but Step 1 MUST be explicit.
+ if (currentStep === 3 || currentStep === 4) {
+ // ... existing logic for these steps if we want to keep it,
+ // but typically "Back" in a wizard should go to previous wizard step.
+ // However, the original code had this specific logic.
+ // Let's defer to prevStep() for wizard navigation, and only use history/dashboard for exit.
+
if (onBack) {
onBack();
} else {
- // Use window.history.back() as fallback for more reliable navigation
if (window.history.length > 1) {
window.history.back();
} else {
- // If no history, navigate to dashboard
navigate('/dashboard', { replace: true });
}
}
diff --git a/src/services/workflowTemplateApi.ts b/src/services/workflowTemplateApi.ts
index 4460f6a..ecfc39d 100644
--- a/src/services/workflowTemplateApi.ts
+++ b/src/services/workflowTemplateApi.ts
@@ -13,12 +13,35 @@ export interface WorkflowTemplate {
fields?: any;
}
+// Simple in-memory cache
+let templatesCache: WorkflowTemplate[] | null = null;
+
+export const getCachedTemplates = () => templatesCache;
+
export const createTemplate = async (templateData: Partial): Promise => {
const response = await apiClient.post('/templates', templateData);
+ // Invalidate cache or add to it
+ if (templatesCache) templatesCache.push(response.data.data);
return response.data.data;
};
export const getTemplates = async (): Promise => {
const response = await apiClient.get('/templates');
+ templatesCache = response.data.data;
+ return response.data.data;
+};
+
+export const deleteTemplate = async (id: string): Promise => {
+ await apiClient.delete(`/templates/${id}`);
+ if (templatesCache) {
+ templatesCache = templatesCache.filter(t => t.id !== id);
+ }
+};
+
+export const updateTemplate = async (id: string, templateData: Partial): Promise => {
+ const response = await apiClient.put(`/templates/${id}`, templateData);
+ if (templatesCache) {
+ templatesCache = templatesCache.map(t => t.id === id ? response.data.data : t);
+ }
return response.data.data;
};