diff --git a/src/app/components/ProjectCard.tsx b/src/app/components/ProjectCard.tsx
index efae0f9..f89fbae 100644
--- a/src/app/components/ProjectCard.tsx
+++ b/src/app/components/ProjectCard.tsx
@@ -32,6 +32,7 @@ export function ProjectCard({
groupName={project.group?.name ?? 'ungrouped'}
members={project.members}
needsHelp={project.needsHelp}
+ hasVideo={project.hasVideo}
voteCategories={voteCategories}
/>
);
@@ -62,6 +63,7 @@ export function ProjectListItem({
detail,
members,
needsHelp = false,
+ hasVideo = false,
emptyMemberLabel = 'up for grabs',
voteCategories = [],
}: {
@@ -74,6 +76,7 @@ export function ProjectListItem({
detail?: string;
members: ProjectListMember[];
needsHelp?: boolean;
+ hasVideo?: boolean;
emptyMemberLabel?: string;
voteCategories?: string[];
}) {
@@ -96,6 +99,7 @@ export function ProjectListItem({
{groupName}
{detail &&
{detail}}
+
{needsHelp &&
looking for help}
@@ -124,11 +128,16 @@ function ProjectTags({project, className}: {project: ProjectSummary; className:
{project.kind === 'idea' ? 'open idea' : (project.group?.name ?? 'ungrouped')}
+
{project.needsHelp && looking for help}
);
}
+function ProjectVideoTag({hasVideo}: {hasVideo: boolean}) {
+ return hasVideo ? has video : null;
+}
+
export function MemberStack({
members,
emptyLabel = 'up for grabs',
diff --git a/src/app/queries/projects.ts b/src/app/queries/projects.ts
index f7f3a3a..2033391 100644
--- a/src/app/queries/projects.ts
+++ b/src/app/queries/projects.ts
@@ -39,6 +39,7 @@ export function useProjects(
kind?: 'project' | 'idea',
group?: string,
search?: string,
+ hasVideo?: boolean,
cursor?: string,
) {
const query = new URLSearchParams({
@@ -48,9 +49,10 @@ export function useProjects(
if (kind) query.set('kind', kind);
if (group) query.set('group', group);
if (search) query.set('q', search);
+ if (hasVideo) query.set('hasVideo', 'true');
if (cursor) query.set('cursor', cursor);
return useQuery({
- queryKey: ['projects', yearId, kind, group, search, cursor ?? null],
+ queryKey: ['projects', yearId, kind, group, search, hasVideo, cursor ?? null],
queryFn: () => apiRequest(`/projects?${query}`),
placeholderData: keepPreviousData,
});
diff --git a/src/app/routes/ProjectsPage.tsx b/src/app/routes/ProjectsPage.tsx
index b782ea4..87ab73c 100644
--- a/src/app/routes/ProjectsPage.tsx
+++ b/src/app/routes/ProjectsPage.tsx
@@ -38,6 +38,7 @@ export function ProjectsPage({isAdmin = false}: {isAdmin?: boolean}) {
const [searchParams, setSearchParams] = useSearchParams();
const [kind, setKind] = useState<'project' | 'idea'>('project');
const group = searchParams.get('group') ?? '';
+ const [hasVideoOnly, setHasVideoOnly] = useState(false);
const [searchInput, setSearchInput] = useState('');
const [search, setSearch] = useState('');
const [cursor, setCursor] = useState();
@@ -52,6 +53,7 @@ export function ProjectsPage({isAdmin = false}: {isAdmin?: boolean}) {
kind,
kind === 'project' ? group || undefined : undefined,
search || undefined,
+ kind === 'project' && hasVideoOnly ? true : undefined,
cursor,
);
const error = year.error ?? projects.error;
@@ -215,6 +217,7 @@ export function ProjectsPage({isAdmin = false}: {isAdmin?: boolean}) {
className={kind === 'idea' ? 'active' : ''}
onClick={() => {
setKind('idea');
+ setHasVideoOnly(false);
resetPagination();
}}
>
@@ -238,6 +241,19 @@ export function ProjectsPage({isAdmin = false}: {isAdmin?: boolean}) {
)}
+ {kind === 'project' && (
+
+ )}
{(['grid', 'list'] as const).map((option) => (