diff --git a/apps/platform/src/features/resources/components/resourcesList.tsx b/apps/platform/src/features/resources/components/resourcesList.tsx index 74e9f1b..9bbbe28 100644 --- a/apps/platform/src/features/resources/components/resourcesList.tsx +++ b/apps/platform/src/features/resources/components/resourcesList.tsx @@ -1,15 +1,84 @@ +import { LockIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { Button, Input } from "@opencircle/ui"; +import { useState } from "react"; +import { useAccount } from "../../../features/auth/hooks/useAccount"; +import { api } from "../../../utils/api"; import { useResources } from "../hooks/useResources"; import { ResourceCard } from "./resourceCard"; +import { ResourcesListSkeleton } from "./resourcesListSkeleton"; interface ResourcesListProps { channelId?: string; } export const ResourcesList = ({ channelId }: ResourcesListProps) => { - const { resources, isResourcesLoading } = useResources(channelId); + const { resources, isResourcesLoading, error } = useResources(channelId); + const [inviteCode, setInviteCode] = useState(""); + const [isSubmitting, setIsSubmitting] = useState(false); + const { account } = useAccount(); + + const handleRequestAccess = async () => { + if (!inviteCode.trim()) return; + + setIsSubmitting(true); + try { + if (!account?.id) { + alert("Please log in to request access"); + return; + } + + const response = await api.inviteCodes.validate({ + code: inviteCode, + user_id: account.id, + }); + + if (response.valid) { + // Successfully validated - refresh resources to show content + window.location.reload(); + } else { + alert(response.message || "Failed to validate invite code"); + } + } catch (err) { + console.error("Error validating invite code:", err); + alert("An error occurred while validating the invite code"); + } finally { + setIsSubmitting(false); + } + }; if (isResourcesLoading) { - return
Loading resources...
; + return ; + } + + if (error) { + return ( +
+
+ +
+
+ You are not eligible to access this content. +
+ {account?.id && ( +
+ setInviteCode(e.target.value)} + /> + +
+ )} +
+ ); } if (!resources || resources.length === 0) { diff --git a/apps/platform/src/features/resources/components/resourcesListSkeleton.tsx b/apps/platform/src/features/resources/components/resourcesListSkeleton.tsx new file mode 100644 index 0000000..2c54702 --- /dev/null +++ b/apps/platform/src/features/resources/components/resourcesListSkeleton.tsx @@ -0,0 +1,32 @@ +export const ResourcesListSkeleton = () => { + return ( +
+ {Array.from({ length: 5 }).map((_, index) => ( +
+
+
+ {/* URL link skeleton */} +
+
+
+
+ + {/* Description skeleton - only show if there might be one */} +
+
+
+
+ + {/* Footer info skeleton */} +
+
+
+
+
+
+
+
+ ))} +
+ ); +}; diff --git a/apps/platform/src/features/resources/hooks/useResources.ts b/apps/platform/src/features/resources/hooks/useResources.ts index b8b1546..a0602c0 100644 --- a/apps/platform/src/features/resources/hooks/useResources.ts +++ b/apps/platform/src/features/resources/hooks/useResources.ts @@ -1,8 +1,9 @@ import { useQuery } from "@tanstack/react-query"; +import { HTTPError } from "ky"; import { api } from "../../../utils/api"; export const useResources = (channelId?: string) => { - const { data, isLoading } = useQuery({ + const { data, isLoading, error } = useQuery({ queryKey: ["resources", { channelId }], queryFn: async () => { if (channelId) { @@ -10,10 +11,18 @@ export const useResources = (channelId?: string) => { } return await api.resources.getAll(); }, + retry: (failureCount, error) => { + if (error instanceof HTTPError && error.response.status === 403) { + console.error("Not Eligible to access"); + return false; + } + return failureCount < 3; + }, }); return { resources: data, isResourcesLoading: isLoading, + error, }; };