Set not found
-
+
);
}
-
-interface ArtistVotingButtonsProps {
- userVote: number | null;
- onVote: (voteType: number) => void;
- getVoteCount: (voteType: number) => number;
-}
-
-export function ArtistVotingButtons({
- userVote,
- onVote,
- getVoteCount,
-}: ArtistVotingButtonsProps) {
- return (
-
- onVote(2)}
- count={getVoteCount(2)}
- />
- onVote(1)}
- count={getVoteCount(1)}
- />
- onVote(-1)}
- count={getVoteCount(-1)}
- />
-
- );
-}
diff --git a/src/pages/SetDetails/notes/CreateNoteForm.tsx b/src/pages/SetDetails/notes/CreateNoteForm.tsx
new file mode 100644
index 0000000..02b9c7c
--- /dev/null
+++ b/src/pages/SetDetails/notes/CreateNoteForm.tsx
@@ -0,0 +1,70 @@
+import { Button } from "@/components/ui/button";
+import { Textarea } from "@/components/ui/textarea";
+import { useCreateNoteMutation } from "@/hooks/queries/artists/notes/useCreateNoteMutation";
+import { SaveIcon, XIcon } from "lucide-react";
+import { useState } from "react";
+
+export function CreateNoteForm({
+ onSuccess,
+ userId,
+ setId,
+}: {
+ onSuccess(): void;
+ userId: string;
+ setId: string;
+}) {
+ const mutation = useCreateNoteMutation();
+
+ const [noteContent, setNoteContent] = useState("");
+
+ return (
+
+ );
+
+ async function handleSave() {
+ if (!userId) {
+ return;
+ }
+
+ mutation.mutate(
+ { setId, userId, noteContent: noteContent.trim() },
+ {
+ onSuccess() {
+ onSuccess();
+ setNoteContent("");
+ },
+ },
+ );
+ }
+
+ function handleCancel() {
+ setNoteContent("");
+ onSuccess();
+ }
+}
diff --git a/src/pages/SetDetails/notes/SetNoteItem.tsx b/src/pages/SetDetails/notes/SetNoteItem.tsx
new file mode 100644
index 0000000..44ef8f5
--- /dev/null
+++ b/src/pages/SetDetails/notes/SetNoteItem.tsx
@@ -0,0 +1,47 @@
+import { Button } from "@/components/ui/button";
+import { SetNote } from "@/hooks/queries/artists/notes/types";
+import { useDeleteNoteMutation } from "@/hooks/queries/artists/notes/useDeleteNoteMutation";
+import { Trash2Icon } from "lucide-react";
+
+export function SetNoteItem({
+ isOwn,
+ note,
+}: {
+ isOwn: boolean;
+ note: SetNote;
+}) {
+ const deleteNoteMutation = useDeleteNoteMutation();
+
+ return (
+
+
+
+ By: {note.author_username || note.author_email || "Unknown User"}
+
+ {isOwn && (
+
handleDelete(note.id)}
+ className="border-red-400/50 text-red-400 hover:bg-red-400 hover:text-white"
+ disabled={deleteNoteMutation.isPending}
+ >
+
+
+ )}
+
+
+ {note.note_content}
+
+
+ {new Date(note.updated_at).toLocaleDateString()}
+
+
+ );
+
+ async function handleDelete(noteId: string) {
+ if (window.confirm("Are you sure you want to delete this note?")) {
+ deleteNoteMutation.mutate(noteId, {});
+ }
+ }
+}
diff --git a/src/pages/SetDetails/useSetDetail.ts b/src/pages/SetDetails/useSetDetail.ts
deleted file mode 100644
index 26ddaab..0000000
--- a/src/pages/SetDetails/useSetDetail.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { useMemo } from "react";
-import { useAuth } from "@/contexts/AuthContext";
-import { useOfflineVoting } from "@/hooks/useOfflineVoting";
-import { useUserPermissionsQuery } from "@/hooks/queries/auth/useUserPermissions";
-import { useOfflineSetsData } from "@/hooks/useOfflineSetsData";
-
-export function useSetDetail(setId: string | undefined) {
- const { user, loading: authLoading } = useAuth();
- const { data: canEdit = false, isLoading: isLoadingPermissions } =
- useUserPermissionsQuery(user?.id, "edit_artists");
-
- const setsQuery = useOfflineSetsData();
- const { userVotes, handleVote } = useOfflineVoting(user);
-
- const sets = setsQuery.sets;
- const currentSet = useMemo(() => {
- if (!setId || !sets.length) {
- return null;
- }
-
- return sets.find((a) => a.id === setId) || null;
- }, [setId, sets]);
-
- async function handleVoteAction(voteType: number) {
- if (!setId) return;
- await handleVote(setId, voteType);
- }
-
- function getVoteCount(voteType: number) {
- if (!currentSet) return 0;
- return (
- currentSet.votes?.filter((vote) => vote.vote_type === voteType).length ||
- 0
- );
- }
-
- const netVoteScore = currentSet
- ? 2 * getVoteCount(2) + getVoteCount(1) - getVoteCount(-1)
- : 0;
-
- const userVote = userVotes[setId || ""] || null;
-
- return {
- userVote,
- loading: authLoading || isLoadingPermissions || setsQuery.loading,
- canEdit,
- handleVote: handleVoteAction,
- getVoteCount,
- netVoteScore,
- };
-}
diff --git a/src/services/profileOfflineService.ts b/src/services/profileOfflineService.ts
deleted file mode 100644
index 2f62200..0000000
--- a/src/services/profileOfflineService.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { OfflineProfile, offlineStorage } from "@/lib/offlineStorage";
-
-export const profileOfflineService = {
- async cacheProfile(userId: string, profile: OfflineProfile): Promise
{
- try {
- await offlineStorage.saveProfile(userId, profile);
- } catch (error) {
- console.error("Error caching profile:", error);
- }
- },
-
- async getCachedProfile(userId: string): Promise {
- try {
- return await offlineStorage.getProfile(userId);
- } catch (error) {
- console.error("Error getting cached profile:", error);
- return null;
- }
- },
-
- async clearCachedProfile(userId: string): Promise {
- try {
- await offlineStorage.clearProfile(userId);
- } catch (error) {
- console.error("Error clearing cached profile:", error);
- }
- },
-};
diff --git a/vite.config.ts b/vite.config.ts
index f3a1723..1fcec30 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,7 +1,6 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
-import { componentTagger } from "lovable-tagger";
import { VitePWA } from "vite-plugin-pwa";
// https://vitejs.dev/config/
@@ -12,11 +11,16 @@ export default defineConfig(({ mode }) => ({
},
plugins: [
react(),
- mode === "development" && componentTagger(),
VitePWA({
registerType: "autoUpdate",
+ devOptions: {
+ enabled: mode === "development",
+ type: "module",
+ navigateFallback: "/index.html",
+ },
workbox: {
globPatterns: ["**/*.{js,css,html,ico,png,svg,webp,woff,woff2}"],
+ navigateFallback: "/index.html",
runtimeCaching: [
{
urlPattern: /^https:\/\/qssmaz.*\.supabase\.co\/rest\/v1\//,
@@ -46,7 +50,7 @@ export default defineConfig(({ mode }) => ({
manifest: {
name: "UpLine",
short_name: "UpLine",
- description: "UpLine - Your offline-first Boom Festival companion",
+ description: "UpLine - Your Festival companion",
theme_color: "#7c3aed",
background_color: "#1e1b4b",
display: "standalone",