Files
vibe-kanban/frontend/src/components/dialogs/tasks/TaskTemplateEditDialog.tsx
Louis Knight-Webb ba256bbb42 Update Create GitHub PR style (vibe-kanban) (#850)
* Done! I've successfully updated the CreatePRDialog to use the Alert component pattern, matching the style used in DeleteTaskConfirmationDialog:

- Added `Alert` import from `@/components/ui/alert`
- Replaced the custom error div with `<Alert variant="destructive">`
- Added error clearing when starting PR creation for better UX

The error messages now use a consistent, accessible Alert component across the application.

* Cleanup script changes for task attempt 3757c2b1-becb-4b8f-80ab-03be9bc3f096

* Perfect! I've successfully refactored all dialog error messages to use the consistent Alert component pattern:

##  Completed Changes:

**1. [TaskTemplateEditDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3757-update-create-gi/frontend/src/components/dialogs/tasks/TaskTemplateEditDialog.tsx)**
- Added `Alert` and `AlertDescription` imports
- Replaced simple error div with proper Alert component

**2. [GitHubLoginDialog.tsx](file:///private/var/folders/m1/9q_ct1913z10v6wbnv54j25r0000gn/T/vibe-kanban/worktrees/3757-update-create-gi/frontend/src/components/dialogs/auth/GitHubLoginDialog.tsx)**
- Added `Alert` and `AlertDescription` imports
- Replaced both custom styled error divs with Alert components
- Maintained the same error display locations for proper context

## 🎯 Benefits Achieved:
- **Consistent UI/UX**: All dialogs now use the same error styling
- **Better Accessibility**: Semantic alert components with proper roles
- **Unified Theming**: All errors follow the same design system
- **Maintainability**: Single pattern for error display across the app

All dialog error messages now follow the same pattern as DeleteTaskConfirmationDialog and the updated CreatePRDialog.

* Done! I've simplified all Alert components to use the same pattern as CreatePRDialog:

- **Removed AlertDescription wrapper** from all error messages
- **Updated imports** to only import Alert
- **Consistent pattern**: `<Alert variant="destructive">{error}</Alert>` across all dialogs

Now all dialog error messages use the exact same simple Alert pattern throughout the application.

* Cleanup script changes for task attempt 3757c2b1-becb-4b8f-80ab-03be9bc3f096
2025-09-25 13:33:28 +01:00

178 lines
5.6 KiB
TypeScript

import { useState, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Alert } from '@/components/ui/alert';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from '@/components/ui/dialog';
import { Loader2 } from 'lucide-react';
import { templatesApi } from '@/lib/api';
import type {
TaskTemplate,
CreateTaskTemplate,
UpdateTaskTemplate,
} from 'shared/types';
import NiceModal, { useModal } from '@ebay/nice-modal-react';
export interface TaskTemplateEditDialogProps {
template?: TaskTemplate | null; // null for create mode
projectId?: string;
isGlobal?: boolean;
}
export type TaskTemplateEditResult = 'saved' | 'canceled';
export const TaskTemplateEditDialog =
NiceModal.create<TaskTemplateEditDialogProps>(
({ template, projectId, isGlobal = false }) => {
const modal = useModal();
const [formData, setFormData] = useState({
template_name: '',
title: '',
description: '',
});
const [saving, setSaving] = useState(false);
const [error, setError] = useState<string | null>(null);
const isEditMode = Boolean(template);
useEffect(() => {
if (template) {
setFormData({
template_name: template.template_name,
title: template.title,
description: template.description || '',
});
} else {
setFormData({
template_name: '',
title: '',
description: '',
});
}
setError(null);
}, [template]);
const handleSave = async () => {
if (!formData.template_name.trim() || !formData.title.trim()) {
setError('Template name and title are required');
return;
}
setSaving(true);
setError(null);
try {
if (isEditMode && template) {
const updateData: UpdateTaskTemplate = {
template_name: formData.template_name,
title: formData.title,
description: formData.description || null,
};
await templatesApi.update(template.id, updateData);
} else {
const createData: CreateTaskTemplate = {
project_id: isGlobal ? null : projectId || null,
template_name: formData.template_name,
title: formData.title,
description: formData.description || null,
};
await templatesApi.create(createData);
}
modal.resolve('saved' as TaskTemplateEditResult);
modal.hide();
} catch (err: any) {
setError(err.message || 'Failed to save template');
} finally {
setSaving(false);
}
};
const handleCancel = () => {
modal.resolve('canceled' as TaskTemplateEditResult);
modal.hide();
};
const handleOpenChange = (open: boolean) => {
if (!open) {
handleCancel();
}
};
return (
<Dialog open={modal.visible} onOpenChange={handleOpenChange}>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle>
{isEditMode ? 'Edit Template' : 'Create Template'}
</DialogTitle>
</DialogHeader>
<div className="space-y-4 py-4">
<div>
<Label htmlFor="template-name">Template Name</Label>
<Input
id="template-name"
value={formData.template_name}
onChange={(e) =>
setFormData({ ...formData, template_name: e.target.value })
}
placeholder="e.g., Bug Fix, Feature Request"
disabled={saving}
autoFocus
/>
</div>
<div>
<Label htmlFor="template-title">Default Title</Label>
<Input
id="template-title"
value={formData.title}
onChange={(e) =>
setFormData({ ...formData, title: e.target.value })
}
placeholder="e.g., Fix bug in..."
disabled={saving}
/>
</div>
<div>
<Label htmlFor="template-description">
Default Description
</Label>
<Textarea
id="template-description"
value={formData.description}
onChange={(e) =>
setFormData({ ...formData, description: e.target.value })
}
placeholder="Enter a default description for tasks created with this template"
rows={4}
disabled={saving}
/>
</div>
{error && <Alert variant="destructive">{error}</Alert>}
</div>
<DialogFooter>
<Button
variant="outline"
onClick={handleCancel}
disabled={saving}
>
Cancel
</Button>
<Button onClick={handleSave} disabled={saving}>
{saving && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{isEditMode ? 'Update' : 'Create'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
);