feat: add linked item management to action updates in SWOT analysis
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 5s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 5s
This commit is contained in:
@@ -183,6 +183,7 @@ export async function updateAction(
|
||||
description?: string;
|
||||
priority?: number;
|
||||
status?: string;
|
||||
linkedItemIds?: string[];
|
||||
}
|
||||
) {
|
||||
const session = await auth();
|
||||
|
||||
@@ -66,6 +66,7 @@ export function ActionPanel({
|
||||
const [title, setTitle] = useState('');
|
||||
const [description, setDescription] = useState('');
|
||||
const [priority, setPriority] = useState(1);
|
||||
const [editingSelectedItems, setEditingSelectedItems] = useState<string[]>([]);
|
||||
|
||||
function openCreateModal() {
|
||||
if (selectedItems.length < 2) {
|
||||
@@ -75,6 +76,7 @@ export function ActionPanel({
|
||||
setTitle('');
|
||||
setDescription('');
|
||||
setPriority(1);
|
||||
setEditingSelectedItems([]);
|
||||
setEditingAction(null);
|
||||
setShowModal(true);
|
||||
}
|
||||
@@ -83,6 +85,7 @@ export function ActionPanel({
|
||||
setTitle(action.title);
|
||||
setDescription(action.description || '');
|
||||
setPriority(action.priority);
|
||||
setEditingSelectedItems(action.links.map((link) => link.swotItemId));
|
||||
setEditingAction(action);
|
||||
setShowModal(true);
|
||||
}
|
||||
@@ -90,9 +93,16 @@ export function ActionPanel({
|
||||
function closeModal() {
|
||||
setShowModal(false);
|
||||
setEditingAction(null);
|
||||
setEditingSelectedItems([]);
|
||||
onExitLinkMode();
|
||||
}
|
||||
|
||||
function toggleEditingItem(itemId: string) {
|
||||
setEditingSelectedItems((prev) =>
|
||||
prev.includes(itemId) ? prev.filter((id) => id !== itemId) : [...prev, itemId]
|
||||
);
|
||||
}
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -100,10 +110,15 @@ export function ActionPanel({
|
||||
|
||||
startTransition(async () => {
|
||||
if (editingAction) {
|
||||
if (editingSelectedItems.length < 2) {
|
||||
alert('Une action doit être liée à au moins 2 items SWOT');
|
||||
return;
|
||||
}
|
||||
await updateAction(editingAction.id, sessionId, {
|
||||
title: title.trim(),
|
||||
description: description.trim() || undefined,
|
||||
priority,
|
||||
linkedItemIds: editingSelectedItems,
|
||||
});
|
||||
} else {
|
||||
await createAction(sessionId, {
|
||||
@@ -302,6 +317,48 @@ export function ActionPanel({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{editingAction && (
|
||||
<div className="mb-4">
|
||||
<p className="mb-2 text-sm font-medium text-foreground">
|
||||
Items liés ({editingSelectedItems.length}) :
|
||||
</p>
|
||||
<div className="max-h-48 space-y-2 overflow-y-auto rounded-lg border border-border bg-background p-3">
|
||||
{allItems.map((item) => {
|
||||
const isSelected = editingSelectedItems.includes(item.id);
|
||||
return (
|
||||
<label
|
||||
key={item.id}
|
||||
className={`
|
||||
flex cursor-pointer items-center gap-2 rounded-lg border p-2 transition-colors
|
||||
${
|
||||
isSelected
|
||||
? 'border-primary bg-primary/10'
|
||||
: 'border-border bg-card hover:bg-card-hover'
|
||||
}
|
||||
`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isSelected}
|
||||
onChange={() => toggleEditingItem(item.id)}
|
||||
className="h-4 w-4 rounded border-border text-primary focus:ring-primary"
|
||||
/>
|
||||
<Badge variant={categoryBadgeVariant[item.category]} className="shrink-0">
|
||||
{categoryShort[item.category]}
|
||||
</Badge>
|
||||
<span className="text-sm text-foreground">{item.content}</span>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{editingSelectedItems.length < 2 && (
|
||||
<p className="mt-2 text-xs text-destructive">
|
||||
Sélectionnez au moins 2 items SWOT
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-4">
|
||||
<Input
|
||||
label="Titre de l'action"
|
||||
|
||||
@@ -305,11 +305,39 @@ export async function updateAction(
|
||||
priority?: number;
|
||||
status?: string;
|
||||
dueDate?: Date | null;
|
||||
linkedItemIds?: string[];
|
||||
}
|
||||
) {
|
||||
const { linkedItemIds, ...updateData } = data;
|
||||
|
||||
// If linkedItemIds is provided, update the links
|
||||
if (linkedItemIds !== undefined) {
|
||||
// Delete all existing links
|
||||
await prisma.actionLink.deleteMany({
|
||||
where: { actionId },
|
||||
});
|
||||
|
||||
// Create new links
|
||||
if (linkedItemIds.length > 0) {
|
||||
await prisma.actionLink.createMany({
|
||||
data: linkedItemIds.map((swotItemId) => ({
|
||||
actionId,
|
||||
swotItemId,
|
||||
})),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return prisma.action.update({
|
||||
where: { id: actionId },
|
||||
data,
|
||||
data: updateData,
|
||||
include: {
|
||||
links: {
|
||||
include: {
|
||||
swotItem: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user