Skip to content

Commit

Permalink
fix: loosen vote state schema
Browse files Browse the repository at this point in the history
  • Loading branch information
helmturner committed Jul 7, 2024
1 parent b3eb61b commit e380fae
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 49 deletions.
42 changes: 32 additions & 10 deletions public/docs/api/v0/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -421,17 +421,39 @@
}
},
"ProposalState": {
"type": "object",
"required": ["status", "results", "authorName"],
"properties": {
"authorName": { "type": "string" },
"status": { "type": "string", "enum": ["closed", "open"] },
"userVote": { "$ref": "#/components/schemas/Vote" },
"results": {
"type": "array",
"items": { "$ref": "#/components/schemas/Vote" }
"oneOf": [
{
"type": "object",
"required": ["status", "results", "authorName"],
"properties": {
"authorName": { "type": "string" },
"status": { "type": "string", "enum": ["closed"] },
"userVote": { "$ref": "#/components/schemas/Vote" },
"results": {
"type": "array",
"items": { "$ref": "#/components/schemas/Vote" }
}
}
},
{
"type": "object",
"required": ["status", "authorName"],
"properties": {
"authorName": { "type": "string" },
"status": { "type": "string", "enum": ["open"] },
"userVote": { "$ref": "#/components/schemas/Vote" },
"results": {
"oneOf": [
{
"type": "array",
"items": { "$ref": "#/components/schemas/Vote" }
},
{ "type": "null" }
]
}
}
}
}
]
},
"ProposalIndex": {
"allOf": [
Expand Down
47 changes: 23 additions & 24 deletions src/features/voting/ProposalList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,55 @@ import { Button } from '../ui/button.tsx';
import { sdk, type Paginated } from '../../sdk.ts';
import { useClerk } from '../auth/hooks.ts';
import { LoadingSpinner } from '../ui/LoadingSpinner.tsx';
import type { Clerk } from '../auth/clerk.ts';

// This component auto-loads proposals on scroll, so we hard-code a static limit
const limit = 10;

export function ProposalList() {
const clerk = useClerk();
const clerkClient = useClerk();
const [loading, setLoading] = useState(true);
const [cursor, setCursor] = useState<Paginated['cursor']>();
const [proposals, setProposals] = useState<ProposalCardProps[]>([]);

const load = useCallback(
async (pagination: Paginated) => {
if (!clerk) return;
setLoading(true);
const token = await clerk.session?.getToken();
const load = useCallback(async (pagination: Paginated, clerk: Clerk) => {
if (!clerk) return;
setLoading(true);
const token = await clerk.session?.getToken();

try {
const result = await sdk.listProposals({
queries: { pagination },
headers: token ? { Authorization: `Bearer ${token}` } : {},
});
setCursor(result.cursor);
setProposals((previous) => [...previous, ...result.proposals]);
} finally {
setLoading(false);
}
},
[clerk],
);
try {
const result = await sdk.listProposals({
queries: { pagination },
headers: token ? { Authorization: `Bearer ${token}` } : {},
});
setCursor(result.cursor);
setProposals((previous) => [...previous, ...result.proposals]);
} finally {
setLoading(false);
}
}, []);

useEffect(() => {
if (!clerk) return;
if (!clerkClient) return;
// Load initial proposals
toast.promise(load({ limit }), {
toast.promise(load({ limit }, clerkClient), {
loading: 'Loading proposals...',
success: 'Proposals loaded',
error: 'Failed to load proposals',
});
}, [clerk, load]);
}, [clerkClient, load]);

const onClick = useCallback(() => {
if (loading) return;
if (!cursor) return;
if (!clerkClient) return;

toast.promise(load({ cursor, limit }), {
toast.promise(load({ cursor, limit }, clerkClient), {
loading: 'Loading more proposals...',
success: 'More proposals loaded',
error: 'Failed to load more proposals',
});
}, [loading, load, cursor]);
}, [loading, load, cursor, clerkClient]);

return (
<div>
Expand Down
48 changes: 33 additions & 15 deletions src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,25 @@ export type DatabaseObject = {
created: string;
updated: string;
};
export type ProposalState = {
authorName: string;
/**
* @enum closed, open
*/
status: 'closed' | 'open';
userVote?: Vote | undefined;
results: Array<Vote>;
};
export type ProposalState =
| {
authorName: string;
/**
* @enum closed
*/
status: 'closed';
userVote?: Vote | undefined;
results: Array<Vote>;
}
| {
authorName: string;
/**
* @enum open
*/
status: 'open';
userVote?: Vote | undefined;
results?: (Array<Vote> | null) | undefined;
};
export type Vote = {
/**
* Ranking values: -2 (strong disinterest), -1 (slight disinterest), 0 (neutral), 1 (slight interest), 2 (strong interest)
Expand Down Expand Up @@ -143,12 +153,20 @@ const Vote: z.ZodType<Vote> = z.object({
),
comment: z.union([z.string(), z.null()]).optional(),
});
const ProposalState: z.ZodType<ProposalState> = z.object({
authorName: z.string(),
status: z.enum(['closed', 'open']),
userVote: Vote.optional(),
results: z.array(Vote),
});
const ProposalState: z.ZodType<ProposalState> = z.union([
z.object({
authorName: z.string(),
status: z.literal('closed'),
userVote: Vote.optional(),
results: z.array(Vote),
}),
z.object({
authorName: z.string(),
status: z.literal('open'),
userVote: Vote.optional(),
results: z.union([z.array(Vote), z.null()]).optional(),
}),
]);
const ProposalIndex: z.ZodType<ProposalIndex> = Paginated.and(
z.object({
proposals: z.array(Proposal.and(ProposalState).and(DatabaseObject)),
Expand Down

0 comments on commit e380fae

Please sign in to comment.