-
Notifications
You must be signed in to change notification settings - Fork 18
feat: cut segment list to dedicated GET /api/artists/{id}/segments #1680
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,17 @@ | ||
| import { type Segment } from "@/lib/supabase/getArtistSegments"; | ||
| import { useQuery } from "@tanstack/react-query"; | ||
|
|
||
| async function fetchSegments(artistId: string): Promise<Segment[]> { | ||
| const response = await fetch(`/api/segments?artistId=${artistId}`); | ||
| if (!response.ok) { | ||
| throw new Error("Failed to fetch segments"); | ||
| } | ||
| const segments: Segment[] = await response.json(); | ||
| return segments.filter((s) => s.size > 0); | ||
| } | ||
| import { usePrivy } from "@privy-io/react-auth"; | ||
| import { getArtistSegments } from "@/lib/artists/getArtistSegments"; | ||
|
|
||
| export function useArtistSegments(artistId?: string) { | ||
| const { getAccessToken, authenticated } = usePrivy(); | ||
| return useQuery({ | ||
| queryKey: ["segments", artistId], | ||
| queryFn: () => fetchSegments(artistId!), | ||
| enabled: !!artistId, | ||
| staleTime: 1000 * 60 * 5, // 5 minutes | ||
| queryFn: async () => { | ||
| const accessToken = await getAccessToken(); | ||
| return getArtistSegments(accessToken!, artistId!); | ||
| }, | ||
| enabled: !!artistId && authenticated, | ||
| staleTime: 1000 * 60 * 5, | ||
| refetchOnWindowFocus: false, | ||
| }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,52 @@ | ||||||
| import { getClientApiBaseUrl } from "@/lib/api/getClientApiBaseUrl"; | ||||||
| import type { Segment } from "@/types/Segment"; | ||||||
|
|
||||||
| interface MappedArtistSegment { | ||||||
| id: string; | ||||||
| name: string; | ||||||
| size: number; | ||||||
| icon?: string; | ||||||
| } | ||||||
|
|
||||||
| interface GetArtistSegmentsResponse { | ||||||
| status: "success" | "error"; | ||||||
| segments?: MappedArtistSegment[]; | ||||||
| pagination?: { | ||||||
| total_count: number; | ||||||
| page: number; | ||||||
| limit: number; | ||||||
| total_pages: number; | ||||||
| }; | ||||||
| error?: string; | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Fetches aggregated segments for an artist from the dedicated API. | ||||||
| * | ||||||
| * @param accessToken - Privy access token for Bearer auth | ||||||
| * @param artistId - Artist account ID (path-encoded) | ||||||
| * @returns Consumer `Segment[]` shape, filtered to `size > 0` | ||||||
| */ | ||||||
| export async function getArtistSegments( | ||||||
| accessToken: string, | ||||||
| artistId: string, | ||||||
| ): Promise<Segment[]> { | ||||||
| const response = await fetch( | ||||||
| `${getClientApiBaseUrl()}/api/artists/${artistId}/segments`, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. URL-encode Direct interpolation can produce malformed paths for unexpected IDs. Encode it before composing the URL. Suggested fix- `${getClientApiBaseUrl()}/api/artists/${artistId}/segments`,
+ `${getClientApiBaseUrl()}/api/artists/${encodeURIComponent(artistId)}/segments`,As per coding guidelines, "Implement built-in security practices for authentication and data handling." 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| { | ||||||
| headers: { | ||||||
| Authorization: `Bearer ${accessToken}`, | ||||||
| }, | ||||||
| }, | ||||||
| ); | ||||||
|
|
||||||
| const data: GetArtistSegmentsResponse = await response.json(); | ||||||
|
|
||||||
| if (!response.ok || data.status === "error") { | ||||||
| throw new Error(data.error || "Failed to fetch segments"); | ||||||
| } | ||||||
|
|
||||||
| return (data.segments || []) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This helper returns only Useful? React with 👍 / 👎. |
||||||
| .map((s) => ({ id: s.id, name: s.name, size: s.size, icon: s.icon })) | ||||||
| .filter((s) => s.size > 0); | ||||||
| } | ||||||
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { Tables } from "@/types/database.types"; | ||
|
|
||
| type Social = Tables<"socials">; | ||
|
|
||
| /** | ||
| * Aggregated segment shape consumed by segment list UI | ||
| * (`SegmentsWrapper`, `FanGroupNavItem`, `MiniMenu`, `Segments`, `SegmentButton`). | ||
| * | ||
| * `fans` is optional because the dedicated `GET /api/artists/{id}/segments` | ||
| * endpoint does not return a fan roster; components that render avatars | ||
| * fall back to an empty array. | ||
| */ | ||
| export interface Segment { | ||
| id: string; | ||
| name: string; | ||
| size: number; | ||
| icon?: string; | ||
| fans?: Social[]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
In@privy-io/react-auth, can usePrivy().getAccessToken() return null/undefined even whenauthenticatedis true? Please cite the official docs/type signature.💡 Result:
No, usePrivy.getAccessToken does not return null/undefined when authenticated is true. The official Privy documentation states that when a user is authenticated, Privy issues an app access token, and getAccessToken retrieves this token as a string, automatically refreshing it if expired. The docs show it used without checking authentication first and describe it returning a string. The authenticated boolean from usePrivy indicates the user has a valid session with an access token. If not authenticated, calling getAccessToken would fail (likely throw), but when authenticated is true, it succeeds and returns the token string. No type signature explicitly showing | null was found in docs or npm pages, and examples treat it as Promise<string>.
Citations:
Remove non-null assertions and add explicit error handling for better clarity.
The
enabledguard and Privy's contract ensuregetAccessToken()returns a string whenauthenticatedis true, making the assertions onaccessTokenredundant. However, for production auth code, explicit checks with clear error messages are better practice than relying on assertions.Suggested fix
queryFn: async () => { + if (!artistId) { + throw new Error("Artist ID is required for fetching segments"); + } const accessToken = await getAccessToken(); - return getArtistSegments(accessToken!, artistId!); + return getArtistSegments(accessToken, artistId); },Per Privy documentation,
getAccessToken()returnsPromise<string>whenauthenticatedis true, and throws on error rather than returning null. Theenabledguard prevents query execution when either condition is false, so the assertions are safe but unnecessary. Removing them improves readability and aligns with the guideline to handle edge cases explicitly in auth code.🤖 Prompt for AI Agents