missions mission pages
This commit is contained in:
parent
ff1b5244e6
commit
f45efbedb5
@ -1,101 +0,0 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from "@/app/api/auth/options";
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { deleteMissionLogo } from '@/lib/mission-uploads';
|
||||
import { getPublicUrl, S3_CONFIG } from '@/lib/s3';
|
||||
import { IntegrationService } from '@/lib/services/integration-service';
|
||||
|
||||
// Helper function to check authentication
|
||||
async function checkAuth(request: Request) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session?.user?.id) {
|
||||
console.error('Unauthorized access attempt:', {
|
||||
url: request.url,
|
||||
method: request.method,
|
||||
headers: Object.fromEntries(request.headers)
|
||||
});
|
||||
return { authorized: false, userId: null };
|
||||
}
|
||||
return { authorized: true, userId: session.user.id };
|
||||
}
|
||||
|
||||
// GET endpoint to retrieve a mission by ID
|
||||
export async function GET(request: Request, props: { params: Promise<{ missionId: string }> }) {
|
||||
const params = await props.params;
|
||||
try {
|
||||
const { authorized, userId } = await checkAuth(request);
|
||||
if (!authorized || !userId) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const { missionId } = params;
|
||||
if (!missionId) {
|
||||
return NextResponse.json({ error: 'Mission ID is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Get mission with detailed info
|
||||
const mission = await (prisma as any).mission.findFirst({
|
||||
where: {
|
||||
id: missionId,
|
||||
OR: [
|
||||
{ creatorId: userId },
|
||||
{ missionUsers: { some: { userId } } }
|
||||
]
|
||||
},
|
||||
include: {
|
||||
creator: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true
|
||||
}
|
||||
},
|
||||
missionUsers: {
|
||||
select: {
|
||||
id: true,
|
||||
role: true,
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
attachments: {
|
||||
select: {
|
||||
id: true,
|
||||
filename: true,
|
||||
filePath: true,
|
||||
fileType: true,
|
||||
fileSize: true,
|
||||
createdAt: true
|
||||
},
|
||||
orderBy: { createdAt: 'desc' }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!mission) {
|
||||
return NextResponse.json({ error: 'Mission not found or access denied' }, { status: 404 });
|
||||
}
|
||||
|
||||
// Add public URLs to mission logo and attachments
|
||||
const missionWithUrls = {
|
||||
...mission,
|
||||
logoUrl: mission.logo ? `/api/centrale/image/${mission.logo}` : null,
|
||||
attachments: mission.attachments.map((attachment: { id: string; filename: string; filePath: string; fileType: string; fileSize: number; createdAt: Date }) => ({
|
||||
...attachment,
|
||||
publicUrl: `/api/centrale/image/${attachment.filePath}`
|
||||
}))
|
||||
};
|
||||
|
||||
return NextResponse.json(missionWithUrls);
|
||||
} catch (error) {
|
||||
console.error('Error retrieving mission:', error);
|
||||
return NextResponse.json({
|
||||
error: 'Internal server error',
|
||||
details: error instanceof Error ? error.message : String(error)
|
||||
}, { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -88,7 +88,7 @@ export async function GET(request: Request) {
|
||||
// Transform logo paths to public URLs
|
||||
const missionsWithPublicUrls = missions.map(mission => ({
|
||||
...mission,
|
||||
logo: mission.logo ? `/api/centrale/image/${mission.logo}` : null
|
||||
logo: mission.logo ? `/api/missions/image/${mission.logo}` : null
|
||||
}));
|
||||
|
||||
return NextResponse.json({
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { authOptions } from '@/app/api/auth/options';
|
||||
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { S3_CONFIG } from '@/lib/s3';
|
||||
|
||||
// Initialize S3 client
|
||||
const s3Client = new S3Client({
|
||||
region: S3_CONFIG.region,
|
||||
endpoint: S3_CONFIG.endpoint,
|
||||
credentials: {
|
||||
accessKeyId: S3_CONFIG.accessKey || '',
|
||||
secretAccessKey: S3_CONFIG.secretKey || ''
|
||||
},
|
||||
forcePathStyle: true // Required for MinIO
|
||||
});
|
||||
|
||||
// This endpoint serves mission images from Minio using the server's credentials
|
||||
export async function GET(request: NextRequest, { params }: { params: { path: string[] } }) {
|
||||
try {
|
||||
// Check if path is provided
|
||||
if (!params.path || params.path.length === 0) {
|
||||
console.error('Missing path parameter');
|
||||
return new NextResponse('Path is required', { status: 400 });
|
||||
}
|
||||
|
||||
// Reconstruct the full path from path segments
|
||||
const filePath = params.path.join('/');
|
||||
console.log('Fetching centrale image:', filePath);
|
||||
console.log('S3 bucket being used:', S3_CONFIG.bucket);
|
||||
|
||||
// Create S3 command to get the object
|
||||
const command = new GetObjectCommand({
|
||||
Bucket: S3_CONFIG.bucket, // Use the pages bucket
|
||||
Key: filePath,
|
||||
});
|
||||
|
||||
// Get the object from S3/Minio
|
||||
console.log('Sending S3 request...');
|
||||
const response = await s3Client.send(command);
|
||||
console.log('S3 response received');
|
||||
|
||||
if (!response.Body) {
|
||||
console.error('File not found in Minio:', filePath);
|
||||
return new NextResponse('File not found', { status: 404 });
|
||||
}
|
||||
|
||||
// Log success information
|
||||
console.log('File found, content type:', response.ContentType);
|
||||
console.log('File size:', response.ContentLength, 'bytes');
|
||||
|
||||
// Get the readable web stream directly
|
||||
const stream = response.Body.transformToWebStream();
|
||||
|
||||
// Determine content type
|
||||
const contentType = response.ContentType || 'application/octet-stream';
|
||||
|
||||
// Create and return a new response with the file stream
|
||||
return new NextResponse(stream as ReadableStream, {
|
||||
headers: {
|
||||
'Content-Type': contentType,
|
||||
'Cache-Control': 'public, max-age=31536000', // Cache for 1 year
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error serving centrale image:', error);
|
||||
console.error('Error details:', JSON.stringify(error, null, 2));
|
||||
return new NextResponse('Internal Server Error', { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -87,13 +87,13 @@ export async function GET(request: Request) {
|
||||
const totalCount = await (prisma as any).mission.count({ where });
|
||||
|
||||
// Transform logo paths to public URLs
|
||||
const missionsWithFormatting = missions.map((mission: any) => ({
|
||||
const missionsWithPublicUrls = missions.map((mission: any) => ({
|
||||
...mission,
|
||||
logo: mission.logo ? `/api/centrale/image/${mission.logo}` : null
|
||||
logo: mission.logo ? `/api/missions/image/${mission.logo}` : null
|
||||
}));
|
||||
|
||||
return NextResponse.json({
|
||||
missions: missionsWithFormatting,
|
||||
missions: missionsWithPublicUrls,
|
||||
pagination: {
|
||||
total: totalCount,
|
||||
offset,
|
||||
|
||||
@ -1,67 +1,58 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { MissionsAdminPanel } from "@/components/missions/missions-admin-panel";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ArrowLeft, Home } from "lucide-react";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
|
||||
export default function EditMissionPage({ params }: { params: { missionId: string }}) {
|
||||
export default function EditMissionPage() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { toast } = useToast();
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
const { missionId } = params;
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
// Check if the mission exists
|
||||
const missionId = params.missionId as string;
|
||||
|
||||
useEffect(() => {
|
||||
const checkMission = async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/centrale/${missionId}`);
|
||||
if (!response.ok) {
|
||||
console.error('Mission not found, redirecting to list');
|
||||
router.push('/centrale');
|
||||
}
|
||||
setIsLoading(false);
|
||||
} catch (error) {
|
||||
console.error('Error checking mission:', error);
|
||||
router.push('/centrale');
|
||||
}
|
||||
};
|
||||
toast({
|
||||
title: "Fonctionnalité en développement",
|
||||
description: "L'édition de mission sera bientôt disponible.",
|
||||
variant: "default",
|
||||
});
|
||||
|
||||
checkMission();
|
||||
}, [missionId, router]);
|
||||
|
||||
if (isLoading) {
|
||||
return <div className="p-8 text-center">Loading...</div>;
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
}, [toast]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full w-full bg-white">
|
||||
<div className="bg-white border-b border-gray-100 py-3 px-6 flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => router.push(`/centrale/${missionId}`)}
|
||||
className="text-gray-600 hover:text-gray-900"
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
Retour aux détails
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => router.push("/centrale")}
|
||||
className="text-gray-600 hover:text-gray-900"
|
||||
>
|
||||
<Home className="h-4 w-4 mr-2" />
|
||||
Liste des missions
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 overflow-auto bg-white">
|
||||
<MissionsAdminPanel missionId={missionId} />
|
||||
<div className="bg-gray-50 min-h-screen p-6">
|
||||
<div className="bg-white rounded-lg shadow-sm border border-gray-100 mb-6 p-6">
|
||||
<h1 className="text-2xl font-bold text-gray-900 mb-6">Modifier la mission</h1>
|
||||
|
||||
{loading ? (
|
||||
<div className="flex justify-center my-12">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-600"></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-6">
|
||||
<p className="text-gray-500">
|
||||
La fonctionnalité d'édition de mission est en cours de développement et sera disponible prochainement.
|
||||
</p>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<Button
|
||||
onClick={() => router.push(`/missions/${missionId}`)}
|
||||
variant="outline"
|
||||
>
|
||||
Retour à la mission
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => router.push("/missions")}
|
||||
>
|
||||
Voir toutes les missions
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -56,18 +56,18 @@ export default function MissionDetailPage() {
|
||||
const fetchMissionDetails = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch(`/api/centrale/${missionId}`);
|
||||
const response = await fetch(`/api/missions/${missionId}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch mission details');
|
||||
}
|
||||
const data = await response.json();
|
||||
console.log("Mission details:", data);
|
||||
setMission(data.mission);
|
||||
setMission(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching mission details:', error);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to load mission details",
|
||||
title: "Erreur",
|
||||
description: "Impossible de charger les détails de la mission",
|
||||
variant: "destructive",
|
||||
});
|
||||
} finally {
|
||||
@ -137,7 +137,7 @@ export default function MissionDetailPage() {
|
||||
|
||||
// Handle edit mission
|
||||
const handleEditMission = () => {
|
||||
router.push(`/centrale/${missionId}/edit`);
|
||||
router.push(`/missions/${missionId}/edit`);
|
||||
};
|
||||
|
||||
// Handle delete mission
|
||||
@ -148,7 +148,7 @@ export default function MissionDetailPage() {
|
||||
|
||||
try {
|
||||
setDeleting(true);
|
||||
const response = await fetch(`/api/centrale/${missionId}`, {
|
||||
const response = await fetch(`/api/missions/${missionId}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
@ -157,17 +157,17 @@ export default function MissionDetailPage() {
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Mission deleted successfully",
|
||||
title: "Mission supprimée",
|
||||
description: "La mission a été supprimée avec succès",
|
||||
});
|
||||
|
||||
// Redirect back to missions list
|
||||
router.push('/centrale');
|
||||
router.push('/missions');
|
||||
} catch (error) {
|
||||
console.error('Error deleting mission:', error);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to delete mission",
|
||||
title: "Erreur",
|
||||
description: "Impossible de supprimer la mission",
|
||||
variant: "destructive",
|
||||
});
|
||||
} finally {
|
||||
|
||||
@ -4,7 +4,7 @@ import React from "react";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export default function CentraleLayout({
|
||||
export default function MissionsLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
@ -24,13 +24,13 @@ export default function CentraleLayout({
|
||||
|
||||
{/* Navigation links */}
|
||||
<nav className="mt-4">
|
||||
<Link href="/centrale" passHref>
|
||||
<div className={`px-6 py-[10px] ${pathname === "/centrale" ? "bg-white" : ""} hover:bg-white`}>
|
||||
<span className="text-sm font-normal text-gray-700">Centrale</span>
|
||||
<Link href="/missions" passHref>
|
||||
<div className={`px-6 py-[10px] ${pathname === "/missions" ? "bg-white" : ""} hover:bg-white`}>
|
||||
<span className="text-sm font-normal text-gray-700">Mes Missions</span>
|
||||
</div>
|
||||
</Link>
|
||||
<Link href="/centrale/new" passHref>
|
||||
<div className={`px-6 py-[10px] ${pathname === "/centrale/new" ? "bg-white" : ""} hover:bg-white`}>
|
||||
<Link href="/missions/new" passHref>
|
||||
<div className={`px-6 py-[10px] ${pathname === "/missions/new" ? "bg-white" : ""} hover:bg-white`}>
|
||||
<span className="text-sm font-normal text-gray-700">Nouvelle Mission</span>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
@ -1,27 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { MissionsAdminPanel } from "@/components/missions/missions-admin-panel";
|
||||
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator } from "@/components/ui/breadcrumb";
|
||||
import Link from "next/link";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
|
||||
export default function NewMissionPage() {
|
||||
return (
|
||||
<div className="w-full h-full bg-white flex flex-col">
|
||||
{/* Breadcrumb navigation */}
|
||||
<nav className="flex px-6 py-3 text-sm text-gray-500 border-b border-gray-100">
|
||||
<ol className="flex items-center space-x-2">
|
||||
<li>
|
||||
<Link href="/centrale">Centrale</Link>
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<ChevronRight className="h-4 w-4 mx-1" />
|
||||
<span className="text-gray-900">Nouvelle mission</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div className="flex flex-col h-full w-full bg-white">
|
||||
<div className="bg-white border-b border-gray-100 py-2 px-4">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink asChild>
|
||||
<Link href="/missions">Missions</Link>
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink>Poster une Mission</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
|
||||
{/* Mission admin panel for creating a new mission */}
|
||||
<div className="flex-1 overflow-auto">
|
||||
<div className="flex-1 overflow-auto p-4 bg-white">
|
||||
<MissionsAdminPanel />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -36,7 +36,7 @@ interface Mission {
|
||||
intention?: string;
|
||||
}
|
||||
|
||||
export default function CentralePage() {
|
||||
export default function MissionsPage() {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [missions, setMissions] = useState<Mission[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@ -47,7 +47,7 @@ export default function CentralePage() {
|
||||
const fetchMissions = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch('/api/centrale');
|
||||
const response = await fetch('/api/missions');
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch missions');
|
||||
}
|
||||
@ -224,16 +224,14 @@ export default function CentralePage() {
|
||||
<div className="w-48 h-48 relative">
|
||||
{mission.logo ? (
|
||||
<img
|
||||
src={mission.logo}
|
||||
src={mission.logo || ''}
|
||||
alt={mission.name}
|
||||
className="w-full h-full object-cover rounded-md"
|
||||
onError={(e) => {
|
||||
console.error("Logo failed to load:", mission.logo);
|
||||
console.error("Full URL attempted:", window.location.origin + mission.logo);
|
||||
|
||||
console.log("Logo failed to load:", mission.logo);
|
||||
console.log("Full URL attempted:", mission.logo);
|
||||
// If the image fails to load, show the fallback
|
||||
(e.currentTarget as HTMLImageElement).style.display = 'none';
|
||||
|
||||
// Show the fallback div
|
||||
const fallbackDiv = e.currentTarget.parentElement?.querySelector('.logo-fallback');
|
||||
if (fallbackDiv) {
|
||||
@ -280,7 +278,7 @@ export default function CentralePage() {
|
||||
Créée le {formatDate(mission.createdAt)}
|
||||
</span>
|
||||
|
||||
<Link href={`/centrale/${mission.id}`}>
|
||||
<Link href={`/missions/${mission.id}`}>
|
||||
<Button className="bg-blue-600 hover:bg-blue-700 text-white text-xs px-3 py-1 h-7 rounded-md">
|
||||
Voir détails
|
||||
</Button>
|
||||
@ -300,7 +298,7 @@ export default function CentralePage() {
|
||||
<p className="text-gray-500 mb-6 max-w-md mx-auto">
|
||||
Créez votre première mission pour commencer à organiser vos projets et inviter des participants.
|
||||
</p>
|
||||
<Link href="/centrale/new">
|
||||
<Link href="/missions/new">
|
||||
<Button className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2">
|
||||
Créer une nouvelle mission
|
||||
</Button>
|
||||
|
||||
@ -28,7 +28,6 @@ import {
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { toast } from '@/components/ui/use-toast';
|
||||
import { FileUpload } from './file-upload';
|
||||
import Link from 'next/link';
|
||||
|
||||
interface Attachment {
|
||||
id: string;
|
||||
@ -74,7 +73,7 @@ export function AttachmentsList({
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await fetch(`/api/centrale/${missionId}/attachments`);
|
||||
const response = await fetch(`/api/missions/${missionId}/attachments`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch attachments');
|
||||
}
|
||||
@ -108,7 +107,7 @@ export function AttachmentsList({
|
||||
if (!deleteAttachment) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/centrale/${missionId}/attachments/${deleteAttachment.id}`, {
|
||||
const response = await fetch(`/api/missions/${missionId}/attachments/${deleteAttachment.id}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
@ -248,13 +247,12 @@ export function AttachmentsList({
|
||||
asChild
|
||||
className="text-gray-500 hover:text-gray-700 hover:bg-gray-100"
|
||||
>
|
||||
<Link
|
||||
href={`/api/centrale/${missionId}/attachments/download/${attachment.id}`}
|
||||
target="_blank"
|
||||
className="text-blue-600 hover:text-blue-800"
|
||||
<a
|
||||
href={`/api/missions/${missionId}/attachments/download/${attachment.id}`}
|
||||
download={attachment.filename}
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
</Link>
|
||||
</a>
|
||||
</Button>
|
||||
|
||||
{allowDelete && (
|
||||
|
||||
@ -402,7 +402,7 @@ export function MissionsAdminPanel() {
|
||||
};
|
||||
|
||||
// Send to API
|
||||
const response = await fetch('/api/centrale', {
|
||||
const response = await fetch('/api/missions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -431,7 +431,7 @@ export function MissionsAdminPanel() {
|
||||
logoFormData.append('missionId', newMissionId);
|
||||
logoFormData.append('type', 'logo');
|
||||
|
||||
const logoResponse = await fetch('/api/centrale/upload', {
|
||||
const logoResponse = await fetch('/api/missions/upload', {
|
||||
method: 'POST',
|
||||
body: logoFormData
|
||||
});
|
||||
@ -468,7 +468,7 @@ export function MissionsAdminPanel() {
|
||||
attachmentFormData.append('type', 'attachment');
|
||||
|
||||
try {
|
||||
const attachmentResponse = await fetch('/api/centrale/upload', {
|
||||
const attachmentResponse = await fetch('/api/missions/upload', {
|
||||
method: 'POST',
|
||||
body: attachmentFormData
|
||||
});
|
||||
@ -512,7 +512,7 @@ export function MissionsAdminPanel() {
|
||||
});
|
||||
|
||||
// Redirect to missions list
|
||||
router.push('/centrale');
|
||||
router.push('/missions');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating mission:', error);
|
||||
|
||||
@ -146,9 +146,9 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) {
|
||||
iframe: process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL,
|
||||
},
|
||||
{
|
||||
title: "Mes Missions",
|
||||
title: "Missions",
|
||||
icon: Kanban,
|
||||
href: "/centrale",
|
||||
href: "/missions",
|
||||
iframe: process.env.NEXT_PUBLIC_IFRAME_MISSIONSBOARD_URL,
|
||||
},
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user