feat: add attachments
This commit is contained in:
parent
a89546c54e
commit
6428126514
4 changed files with 61 additions and 31 deletions
|
|
@ -1,16 +1,16 @@
|
||||||
import { FileText, Image, File } from "lucide-react";
|
import { FileText, Image, File } from "lucide-react";
|
||||||
|
import type { Attachment } from "~/lib/api";
|
||||||
|
|
||||||
export default function AttachmentItem({ attachment }: { attachment: string }) {
|
export default function AttachmentItem({ attachment }: { attachment: Attachment }) {
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
// TODO: BAD: hardcoded URL, should be dynamic (environment variable or config)
|
href={"https://bjcolle.fr/" + attachment.path}
|
||||||
href={"https://bjcolle.fr/" + attachment}
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="flex items-center gap-2 p-3 border rounded-md hover:bg-muted transition-colors cursor-pointer"
|
className="flex items-center gap-2 p-3 border rounded-md hover:bg-muted transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
{getIcon(attachment)}
|
{getIcon(attachment.name)}
|
||||||
<span className="font-medium truncate">
|
<span className="font-medium truncate">
|
||||||
{getName(attachment) || "Sans Nom"}
|
{attachment.name}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
|
@ -44,9 +44,3 @@ const getIcon = (attachment: string) => {
|
||||||
return <File className="h-5 w-5 text-gray-500" />;
|
return <File className="h-5 w-5 text-gray-500" />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getName = (attachment: string) => {
|
|
||||||
const parts = attachment.replace("pj_doc", "").split("_");
|
|
||||||
const nameParts = parts.slice(2); // remove the first two parts
|
|
||||||
return nameParts.join("_");
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import type { Colle, UserPreferences } from "~/lib/api";
|
||||||
|
|
||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
import { Card } from "~/components/ui/card";
|
import { Card } from "~/components/ui/card";
|
||||||
import { User, Star, CalendarDays, MapPin } from "lucide-react";
|
import { User, Star, CalendarDays, MapPin, Paperclip } from "lucide-react";
|
||||||
import { Badge } from "~/components/ui/badge";
|
import { Badge } from "~/components/ui/badge";
|
||||||
import {
|
import {
|
||||||
cn,
|
cn,
|
||||||
|
|
@ -35,8 +35,11 @@ export default function ColleCard({
|
||||||
// onToggleFavorite(colle.id, newValue);
|
// onToggleFavorite(colle.id, newValue);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
const subjectColor = getColorClass(getSubjectColor(colle.subject.name, preferences));
|
const subjectColor = getColorClass(
|
||||||
|
getSubjectColor(colle.subject.name, preferences)
|
||||||
|
);
|
||||||
const subjectEmoji = getSubjectEmoji(colle.subject.name, preferences);
|
const subjectEmoji = getSubjectEmoji(colle.subject.name, preferences);
|
||||||
|
const attachmentsCount = colle.attachments?.length || 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={`/colles/${colle.id}`}>
|
<Link to={`/colles/${colle.id}`}>
|
||||||
|
|
@ -114,13 +117,12 @@ export default function ColleCard({
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* TODO: Attachments */}
|
{attachmentsCount > 0 && (
|
||||||
{/* {colle.attachmentsCount > 0 && (
|
<div className="flex items-center gap-1 text-muted-foreground">
|
||||||
<div className="flex items-center gap-1 text-muted-foreground">
|
<Paperclip className="h-3.5 w-3.5" />
|
||||||
<Paperclip className="h-3.5 w-3.5" />
|
<span className="text-xs">{attachmentsCount}</span>
|
||||||
<span className="text-xs">{colle.attachmentsCount}</span>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)} */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ export interface Colle {
|
||||||
bjid?: string; // Optional field
|
bjid?: string; // Optional field
|
||||||
content?: string; // Optional field
|
content?: string; // Optional field
|
||||||
comment?: string; // Optional field
|
comment?: string; // Optional field
|
||||||
attachments?: string[]; // Optional field, array of attachment URLs
|
attachments?: Attachment[]; // Optional field, array of attachment URLs
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CollePayload {
|
interface CollePayload {
|
||||||
|
|
@ -278,6 +278,20 @@ export const useColle = (id: number) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const refreshColle = async (id: number) => {
|
||||||
|
return makePostRequest(
|
||||||
|
`/colles/${id}/refresh`,
|
||||||
|
{},
|
||||||
|
"Échec de la demande de rafraîchissement de la colle",
|
||||||
|
"POST"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface Attachment {
|
||||||
|
path: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* === SUBJECTS API ===
|
* === SUBJECTS API ===
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,10 @@ import ColleDetailsSkeleton from "~/components/details/skeleton-details";
|
||||||
import AttachmentItem from "~/components/details/attachment";
|
import AttachmentItem from "~/components/details/attachment";
|
||||||
import Error from "~/components/error";
|
import Error from "~/components/error";
|
||||||
import { Badge } from "~/components/ui/badge";
|
import { Badge } from "~/components/ui/badge";
|
||||||
import { AUTH_ERROR, useColle, useUser } from "~/lib/api";
|
import { AUTH_ERROR, refreshColle, useColle, useUser } from "~/lib/api";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { formatDate, formatGrade, formatTime, goBack } from "~/lib/utils";
|
import { formatDate, formatGrade, formatTime, goBack } from "~/lib/utils";
|
||||||
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
// TODO: Preferences for subject colors
|
// TODO: Preferences for subject colors
|
||||||
const getSubjectColor = (_: string) => {
|
const getSubjectColor = (_: string) => {
|
||||||
|
|
@ -42,10 +43,17 @@ const getSubjectEmoji = (_: string) => {
|
||||||
// TODO: Move all code to components
|
// TODO: Move all code to components
|
||||||
export default function ColleDetailPage() {
|
export default function ColleDetailPage() {
|
||||||
const { user, isLoading: isUserLoading, error: userError } = useUser();
|
const { user, isLoading: isUserLoading, error: userError } = useUser();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const params = useParams<{ colleId: string }>();
|
const params = useParams<{ colleId: string }>();
|
||||||
|
|
||||||
|
const colleId = parseInt(params.colleId!);
|
||||||
|
if (isNaN(colleId)) {
|
||||||
|
return <Navigate to="/" />;
|
||||||
|
}
|
||||||
|
const { colle, error, isLoading } = useColle(colleId);
|
||||||
|
|
||||||
const [isReloading, setIsReloading] = useState(false);
|
const [isReloading, setIsReloading] = useState(false);
|
||||||
|
|
||||||
if (isUserLoading) {
|
if (isUserLoading) {
|
||||||
|
|
@ -61,12 +69,6 @@ export default function ColleDetailPage() {
|
||||||
// TODO: Favorite toggle function
|
// TODO: Favorite toggle function
|
||||||
const toggleStar = () => {};
|
const toggleStar = () => {};
|
||||||
|
|
||||||
const colleId = parseInt(params.colleId!);
|
|
||||||
if (isNaN(colleId)) {
|
|
||||||
return <Navigate to="/" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { colle, error, isLoading } = useColle(colleId);
|
|
||||||
if (error)
|
if (error)
|
||||||
return (
|
return (
|
||||||
<Error
|
<Error
|
||||||
|
|
@ -82,7 +84,26 @@ export default function ColleDetailPage() {
|
||||||
|
|
||||||
const handleReload = () => {
|
const handleReload = () => {
|
||||||
setIsReloading(true);
|
setIsReloading(true);
|
||||||
// TODO: HARD RELOAD
|
refreshColle(colle.id)
|
||||||
|
.then(() => {
|
||||||
|
toast("Les données de cette colle vont être mises à jour", {
|
||||||
|
icon: "🔄",
|
||||||
|
description: "Rafraîchissement en cours...",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Error refreshing colle:", error);
|
||||||
|
toast.error("Échec du rafraîchissement de la colle", {
|
||||||
|
icon: "❌",
|
||||||
|
description: "Veuillez réessayer plus tard.",
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setIsReloading(false);
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ["colle", colle.id],
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleShare = async () => {
|
const handleShare = async () => {
|
||||||
|
|
@ -331,12 +352,11 @@ export default function ColleDetailPage() {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* TODO: Attachments */}
|
|
||||||
{colle.attachments && colle.attachments?.length > 0 && (
|
{colle.attachments && colle.attachments?.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-medium mb-3 flex items-center gap-2">
|
<h3 className="text-lg font-medium mb-3 flex items-center gap-2">
|
||||||
<Paperclip className="h-5 w-5" />
|
<Paperclip className="h-5 w-5" />
|
||||||
Attachments
|
Pièces jointes
|
||||||
</h3>
|
</h3>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
{colle.attachments.map((attachment, index) => (
|
{colle.attachments.map((attachment, index) => (
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue