@@ -339,5 +294,5 @@ export function LoginPopup({
)}
- );
+ )
}
diff --git a/web/src/components/user-display.tsx b/web/src/components/user-display.tsx
index b9fc6f8b..894b131f 100644
--- a/web/src/components/user-display.tsx
+++ b/web/src/components/user-display.tsx
@@ -5,63 +5,53 @@ import { Button } from "@/components/ui/button"
import { pb } from "@/lib/pb"
interface UserDisplayProps {
- userId?: string
- displayName: string
- onClick?: (userId: string, displayName: string) => void
- size?: "sm" | "md" | "lg"
- showAvatar?: boolean
- avatar?: string
+ userId?: string
+ displayName: string
+ onClick?: (userId: string, displayName: string) => void
+ size?: "sm" | "md" | "lg"
+ showAvatar?: boolean
+ avatar?: string
}
const sizeClasses = {
- sm: "h-6 w-6",
- md: "h-8 w-8",
- lg: "h-10 w-10"
+ sm: "h-6 w-6",
+ md: "h-8 w-8",
+ lg: "h-10 w-10",
}
const textSizeClasses = {
- sm: "text-xs",
- md: "text-sm",
- lg: "text-sm"
+ sm: "text-xs",
+ md: "text-sm",
+ lg: "text-sm",
}
-export function UserDisplay({
- userId,
- avatar,
- displayName,
- onClick,
- size = "sm",
- showAvatar = true
-}: UserDisplayProps) {
- // Avatar URL will attempt to load from PocketBase
- // If it doesn't exist, the AvatarFallback will display instead
- const avatarUrl = userId ? `${pb.baseURL}/api/files/_pb_users_auth_/${userId}/${avatar}?thumb=100x100` : undefined
+export function UserDisplay({ userId, avatar, displayName, onClick, size = "sm", showAvatar = true }: UserDisplayProps) {
+ // Avatar URL will attempt to load from PocketBase
+ // If it doesn't exist, the AvatarFallback will display instead
+ const avatarUrl = userId ? `${pb.baseURL}/api/files/_pb_users_auth_/${userId}/${avatar}?thumb=100x100` : undefined
- return (
-
- {showAvatar && (
-
- {avatarUrl && }
-
- {displayName.slice(0, 2).toUpperCase()}
-
-
- )}
- {onClick && userId ? (
-
- ) : (
-
{displayName}
- )}
-
- )
+ return (
+
+ {showAvatar && (
+
+ {avatarUrl && }
+ {displayName.slice(0, 2).toUpperCase()}
+
+ )}
+ {onClick && userId ? (
+
+ ) : (
+
{displayName}
+ )}
+
+ )
}
-
diff --git a/web/src/hooks/use-submissions.ts b/web/src/hooks/use-submissions.ts
index bf264815..6037638e 100644
--- a/web/src/hooks/use-submissions.ts
+++ b/web/src/hooks/use-submissions.ts
@@ -1,140 +1,147 @@
-import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
-import { pb, type Submission } from '@/lib/pb'
-import { toast } from 'sonner'
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
+import { toast } from "sonner"
+import { pb, type Submission } from "@/lib/pb"
// Query key factory
export const submissionKeys = {
- all: ['submissions'] as const,
- lists: () => [...submissionKeys.all, 'list'] as const,
- list: (filters?: Record
) => [...submissionKeys.lists(), filters] as const,
+ all: ["submissions"] as const,
+ lists: () => [...submissionKeys.all, "list"] as const,
+ list: (filters?: Record) => [...submissionKeys.lists(), filters] as const,
}
// Fetch all submissions
export function useSubmissions() {
- return useQuery({
- queryKey: submissionKeys.lists(),
- queryFn: async () => {
- console.log('🔍 Fetching submissions...')
- const records = await pb.collection('submissions').getFullList({
- sort: '-updated',
- expand: 'created_by,approved_by',
- requestKey: null,
- })
-
- console.log('📊 Fetched submissions:', records.length)
- if (records.length > 0) {
- console.log('📋 First submission sample:', records[0])
- console.log('👤 First submission created_by field:', records[0].created_by)
- console.log('🔗 First submission expand data:', (records[0] as any).expand)
- }
-
- return records
- },
- })
+ return useQuery({
+ queryKey: submissionKeys.lists(),
+ queryFn: async () => {
+ console.log("🔍 Fetching submissions...")
+ const records = await pb.collection("submissions").getFullList({
+ sort: "-updated",
+ expand: "created_by,approved_by",
+ requestKey: null,
+ })
+
+ console.log("📊 Fetched submissions:", records.length)
+ if (records.length > 0) {
+ console.log("📋 First submission sample:", records[0])
+ console.log("👤 First submission created_by field:", records[0].created_by)
+ console.log("🔗 First submission expand data:", (records[0] as any).expand)
+ }
+
+ return records
+ },
+ })
}
// Approve submission mutation
export function useApproveSubmission() {
- const queryClient = useQueryClient()
-
- return useMutation({
- mutationFn: async (submissionId: string) => {
- return await pb.collection('submissions').update(submissionId, {
- status: 'approved',
- approved_by: pb.authStore.record?.id || ''
- }, {
- requestKey: null
- })
- },
- onSuccess: (data) => {
- // Invalidate and refetch submissions
- queryClient.invalidateQueries({ queryKey: submissionKeys.lists() })
-
- toast.success("Submission approved", {
- description: "The submission has been approved successfully",
- })
- },
- onError: (error: any) => {
- console.error("Error approving submission:", error)
- if (!error.message?.includes('autocancelled') && !error.name?.includes('AbortError')) {
- toast.error("Failed to approve submission", {
- description: error.message || "An error occurred",
- })
- }
- },
- })
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: async (submissionId: string) => {
+ return await pb.collection("submissions").update(
+ submissionId,
+ {
+ status: "approved",
+ approved_by: pb.authStore.record?.id || "",
+ },
+ {
+ requestKey: null,
+ },
+ )
+ },
+ onSuccess: (data) => {
+ // Invalidate and refetch submissions
+ queryClient.invalidateQueries({ queryKey: submissionKeys.lists() })
+
+ toast.success("Submission approved", {
+ description: "The submission has been approved successfully",
+ })
+ },
+ onError: (error: any) => {
+ console.error("Error approving submission:", error)
+ if (!error.message?.includes("autocancelled") && !error.name?.includes("AbortError")) {
+ toast.error("Failed to approve submission", {
+ description: error.message || "An error occurred",
+ })
+ }
+ },
+ })
}
// Reject submission mutation
export function useRejectSubmission() {
- const queryClient = useQueryClient()
-
- return useMutation({
- mutationFn: async (submissionId: string) => {
- return await pb.collection('submissions').update(submissionId, {
- status: 'rejected',
- approved_by: pb.authStore.record?.id || ''
- }, {
- requestKey: null
- })
- },
- onSuccess: () => {
- // Invalidate and refetch submissions
- queryClient.invalidateQueries({ queryKey: submissionKeys.lists() })
-
- toast.success("Submission rejected", {
- description: "The submission has been rejected",
- })
- },
- onError: (error: any) => {
- console.error("Error rejecting submission:", error)
- if (!error.message?.includes('autocancelled') && !error.name?.includes('AbortError')) {
- toast.error("Failed to reject submission", {
- description: error.message || "An error occurred",
- })
- }
- },
- })
+ const queryClient = useQueryClient()
+
+ return useMutation({
+ mutationFn: async (submissionId: string) => {
+ return await pb.collection("submissions").update(
+ submissionId,
+ {
+ status: "rejected",
+ approved_by: pb.authStore.record?.id || "",
+ },
+ {
+ requestKey: null,
+ },
+ )
+ },
+ onSuccess: () => {
+ // Invalidate and refetch submissions
+ queryClient.invalidateQueries({ queryKey: submissionKeys.lists() })
+
+ toast.success("Submission rejected", {
+ description: "The submission has been rejected",
+ })
+ },
+ onError: (error: any) => {
+ console.error("Error rejecting submission:", error)
+ if (!error.message?.includes("autocancelled") && !error.name?.includes("AbortError")) {
+ toast.error("Failed to reject submission", {
+ description: error.message || "An error occurred",
+ })
+ }
+ },
+ })
}
// Check authentication status
export function useAuth() {
- return useQuery({
- queryKey: ['auth'],
- queryFn: async () => {
- const isValid = pb.authStore.isValid
- const userId = pb.authStore.record?.id
-
- if (!isValid || !userId) {
- return {
- isAuthenticated: false,
- isAdmin: false,
- userId: '',
- }
- }
+ return useQuery({
+ queryKey: ["auth"],
+ queryFn: async () => {
+ const isValid = pb.authStore.isValid
+ const userId = pb.authStore.record?.id
- try {
- // Fetch the full user record to get the admin status
- const user = await pb.collection('users').getOne(userId, {
- requestKey: null,
- })
-
- return {
- isAuthenticated: true,
- isAdmin: user?.admin === true,
- userId: userId,
- }
- } catch (error) {
- console.error('Error fetching user:', error)
- return {
- isAuthenticated: isValid,
- isAdmin: false,
- userId: userId || '',
- }
- }
- },
- staleTime: 5 * 60 * 1000, // 5 minutes
- retry: false,
- })
+ if (!isValid || !userId) {
+ return {
+ isAuthenticated: false,
+ isAdmin: false,
+ userId: "",
+ }
+ }
+
+ try {
+ // Fetch the full user record to get the admin status
+ const user = await pb.collection("users").getOne(userId, {
+ requestKey: null,
+ })
+
+ return {
+ isAuthenticated: true,
+ isAdmin: user?.admin === true,
+ userId: userId,
+ }
+ } catch (error) {
+ console.error("Error fetching user:", error)
+ return {
+ isAuthenticated: isValid,
+ isAdmin: false,
+ userId: userId || "",
+ }
+ }
+ },
+ staleTime: 5 * 60 * 1000, // 5 minutes
+ retry: false,
+ })
}
-
diff --git a/web/src/lib/community.ts b/web/src/lib/community.ts
index 35ee899f..8284e176 100644
--- a/web/src/lib/community.ts
+++ b/web/src/lib/community.ts
@@ -12,18 +12,16 @@ import type { IconWithName } from "@/types/icons"
* Note: Do not use the client-side pb instance (with auth store) on the server
*/
function createServerPB() {
- return new PocketBase(process.env.POCKETBASE_URL || "http://127.0.0.1:8090")
+ return new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL || "http://127.0.0.1:8090")
}
/**
* Transform a CommunityGallery item to IconWithName format for use with IconSearch
*/
function transformGalleryToIcon(item: CommunityGallery): any {
- const pbUrl = process.env.POCKETBASE_URL || "http://127.0.0.1:8090"
-
- const fileUrl = item.assets?.[0]
- ? `${pbUrl}/api/files/community_gallery/${item.id}/${item.assets[0]}`
- : ""
+ const pbUrl = process.env.NEXT_PUBLIC_POCKETBASE_URL || "http://127.0.0.1:8090"
+
+ const fileUrl = item.assets?.[0] ? `${pbUrl}/api/files/community_gallery/${item.id}/${item.assets[0]}` : ""
const transformed = {
name: item.name,
@@ -43,7 +41,7 @@ function transformGalleryToIcon(item: CommunityGallery): any {
wordmark: item.extras?.wordmark,
},
}
-
+
return transformed
}
@@ -62,9 +60,7 @@ export async function fetchCommunitySubmissions(): Promise {
sort: "-created",
})
- return records
- .filter(item => item.assets && item.assets.length > 0)
- .map(transformGalleryToIcon)
+ return records.filter((item) => item.assets && item.assets.length > 0).map(transformGalleryToIcon)
} catch (error) {
console.error("Error fetching community submissions:", error)
return []
@@ -80,4 +76,3 @@ export const getCommunitySubmissions = unstable_cache(fetchCommunitySubmissions,
revalidate: 600,
tags: ["community-gallery"],
})
-
diff --git a/web/src/lib/pb.ts b/web/src/lib/pb.ts
index 311f70b8..08d93358 100644
--- a/web/src/lib/pb.ts
+++ b/web/src/lib/pb.ts
@@ -1,72 +1,71 @@
-import PocketBase, { RecordService } from 'pocketbase';
+import PocketBase, { type RecordService } from "pocketbase"
export interface User {
- id: string
- username: string
- email: string
- admin?: boolean
- avatar?: string
- created: string
- updated: string
+ id: string
+ username: string
+ email: string
+ admin?: boolean
+ avatar?: string
+ created: string
+ updated: string
}
export interface Submission {
- id: string
- name: string
- assets: string[]
- created_by: string
- status: 'approved' | 'rejected' | 'pending' | 'added_to_collection'
- approved_by: string
+ id: string
+ name: string
+ assets: string[]
+ created_by: string
+ status: "approved" | "rejected" | "pending" | "added_to_collection"
+ approved_by: string
expand: {
created_by: User
approved_by: User
}
- extras: {
- aliases: string[]
- categories: string[]
- base?: string
- colors?: {
- dark?: string
- light?: string
- }
- wordmark?: {
- dark?: string
- light?: string
- }
- }
- created: string
- updated: string
+ extras: {
+ aliases: string[]
+ categories: string[]
+ base?: string
+ colors?: {
+ dark?: string
+ light?: string
+ }
+ wordmark?: {
+ dark?: string
+ light?: string
+ }
+ }
+ created: string
+ updated: string
}
export interface CommunityGallery {
- id: string
- name: string
- created_by: string
- status: 'approved' | 'rejected' | 'pending' | 'added_to_collection'
- assets: string[]
+ id: string
+ name: string
+ created_by: string
+ status: "approved" | "rejected" | "pending" | "added_to_collection"
+ assets: string[]
created: string
updated: string
- extras: {
- aliases: string[]
- categories: string[]
- base?: string
- colors?: {
- dark?: string
- light?: string
- }
- wordmark?: {
- dark?: string
- light?: string
- }
- }
+ extras: {
+ aliases: string[]
+ categories: string[]
+ base?: string
+ colors?: {
+ dark?: string
+ light?: string
+ }
+ wordmark?: {
+ dark?: string
+ light?: string
+ }
+ }
}
interface TypedPocketBase extends PocketBase {
- collection(idOrName: string): RecordService // default fallback for any other collection
- collection(idOrName: 'users'): RecordService
- collection(idOrName: 'submissions'): RecordService
- collection(idOrName: 'community_gallery'): RecordService
+ collection(idOrName: string): RecordService // default fallback for any other collection
+ collection(idOrName: "users"): RecordService
+ collection(idOrName: "submissions"): RecordService
+ collection(idOrName: "community_gallery"): RecordService
}
-export const pb = new PocketBase('http://127.0.0.1:8090') as TypedPocketBase;
-
+export const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL || "http://127.0.0.1:8090") as TypedPocketBase
diff --git a/web/src/lib/revalidate.ts b/web/src/lib/revalidate.ts
index 247dc7ff..80d8399c 100644
--- a/web/src/lib/revalidate.ts
+++ b/web/src/lib/revalidate.ts
@@ -19,4 +19,3 @@ export async function revalidateSubmissions() {
revalidatePath("/community")
revalidatePath("/dashboard")
}
-