Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #66 from flowcore-io/38-only-show-users-that-are-r…
…elated-to-specific-conferences-and-have-tickets Added an attendance page
- Loading branch information
Showing
15 changed files
with
318 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { type FC } from "react" | ||
|
||
import { | ||
Select, | ||
SelectContent, | ||
SelectItem, | ||
SelectTrigger, | ||
SelectValue, | ||
} from "@/components/ui/select" | ||
import { type ConferencePreview } from "@/contracts/conference/conference" | ||
import { preventDefaultOnReference } from "@/lib/events/prevent-default-on-reference" | ||
|
||
export type ConferenceSelectionProps = { | ||
conferences: ConferencePreview[] | ||
onSelect: (conferenceId: string) => void | ||
} | ||
|
||
export const ConferenceSelection: FC<ConferenceSelectionProps> = (props) => { | ||
return ( | ||
<Select onValueChange={props.onSelect}> | ||
<SelectTrigger> | ||
<SelectValue placeholder={"Conferences you have tickets for"} /> | ||
</SelectTrigger> | ||
<SelectContent ref={preventDefaultOnReference}> | ||
{props.conferences.map((conference) => ( | ||
<SelectItem key={conference.id} value={conference.id}> | ||
{conference.name} | ||
</SelectItem> | ||
))} | ||
</SelectContent> | ||
</Select> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"use client" | ||
|
||
import { useState } from "react" | ||
|
||
import { ConferenceSelection } from "@/app/attendees/conference-selection" | ||
import { ProfileList } from "@/app/attendees/profile-list.component" | ||
import { NoticeText } from "@/components/ui/messages/notice-text" | ||
import { PageTitle } from "@/components/ui/page-title" | ||
import { api } from "@/trpc/react" | ||
|
||
export default function AttendeesPage() { | ||
const apiFetchAttendingConferences = api.attendance.myConferences.useQuery() | ||
|
||
const [selectedConferenceId, setSelectedConferenceId] = useState<string>("") | ||
|
||
return ( | ||
<div> | ||
<PageTitle | ||
title={"Attendees"} | ||
subtitle={ | ||
"A list of all the people who have tickets for the selected conference" | ||
} | ||
/> | ||
<div className={"mb-5"}> | ||
<ConferenceSelection | ||
conferences={apiFetchAttendingConferences.data ?? []} | ||
onSelect={setSelectedConferenceId} | ||
/> | ||
</div> | ||
|
||
{selectedConferenceId ? ( | ||
<ProfileList conferenceId={selectedConferenceId} /> | ||
) : ( | ||
<NoticeText text={"Select a conference to view attendees"} /> | ||
)} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import Link from "next/link" | ||
import React, { type FC } from "react" | ||
|
||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" | ||
import { type UserProfile } from "@/contracts/profile/user-profile" | ||
|
||
export type ProfileListItemProps = { | ||
profile: UserProfile | ||
} | ||
|
||
export const ProfileListItem: FC<ProfileListItemProps> = ({ profile }) => { | ||
return ( | ||
<Link href={`/profiles/${profile.id}`}> | ||
<li | ||
key={profile.id} | ||
className={"flex items-center space-x-3 border-b border-accent py-3"}> | ||
<Avatar className={"h-12 w-12 flex-grow-0 rounded-full"}> | ||
<AvatarImage src={profile.avatarUrl} alt={profile.displayName} /> | ||
<AvatarFallback className={"rounded"}> | ||
{profile.initials} | ||
</AvatarFallback> | ||
</Avatar> | ||
<div className={"flex-1"}> | ||
<p className={"font-bold"}>{profile.displayName}</p> | ||
<p className={"font-thin"}>{profile.title || "No Title"}</p> | ||
</div> | ||
</li> | ||
</Link> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { cn } from "@/lib/utils" | ||
|
||
export type MissingTextProps = { | ||
text: string | ||
className?: string | ||
} | ||
|
||
/** | ||
* Represents a component for displaying a default missing text with a sad emoji. | ||
* @param text - The text to display. | ||
* @param className - An optional class name to apply to the component. | ||
*/ | ||
export const NoticeText = ({ text, className }: MissingTextProps) => { | ||
return ( | ||
<div className={cn("text-center font-light", className)}> | ||
<p>{text}</p> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* Prevents default behavior on touchend and click events for the given HTML element reference. | ||
* | ||
* @param ref - The HTML element reference on which to prevent default behavior. | ||
* @returns The modified HTML element reference with default behavior prevention on touchend and click events. | ||
* @link https://github.com/radix-ui/primitives/issues/1658#issuecomment-1690666012 | ||
*/ | ||
export const preventDefaultOnReference = (ref: HTMLElement | null) => { | ||
if (!ref) { | ||
return | ||
} | ||
|
||
ref.ontouchend = (e) => { | ||
e.preventDefault() | ||
} | ||
ref.onclick = (e) => { | ||
e.preventDefault() | ||
} | ||
|
||
return ref | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { type FormEvent, type TouchEvent } from "react" | ||
|
||
/** | ||
* A higher-order function that prevents the default behavior of the event and then calls the provided method. | ||
* @param method - The method to call after preventing default behavior. | ||
* @returns A function that takes an event and prevents its default behavior before calling the method. | ||
*/ | ||
export const preventDefault = | ||
(method: () => void) => (e: FormEvent | TouchEvent | MouseEvent) => { | ||
e.preventDefault() | ||
method() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { type MouseEvent } from "react" | ||
|
||
/** | ||
* Stops the propagation of the event and executes the provided method. | ||
* @param method - The method to execute. | ||
* @returns A function that stops event propagation and executes the provided method. | ||
*/ | ||
export const stopPropagation = | ||
(method: () => void) => (e: MouseEvent | TouchEvent) => { | ||
e.stopPropagation() | ||
method() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/server/api/routers/attendance/attendance-my-conferences.procedure.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { desc, eq } from "drizzle-orm" | ||
|
||
import { type ConferencePreview } from "@/contracts/conference/conference" | ||
import { db } from "@/database" | ||
import { conferences, tickets } from "@/database/schemas" | ||
import { protectedProcedure } from "@/server/api/trpc" | ||
|
||
export const attendanceMyConferencesProcedure = protectedProcedure.query( | ||
async ({ ctx }): Promise<ConferencePreview[]> => { | ||
const userId = ctx.user.id | ||
|
||
const conferencesUserIsAttending = await db | ||
.selectDistinct({ conference: conferences }) | ||
.from(conferences) | ||
.leftJoin(tickets, eq(conferences.id, tickets.conferenceId)) | ||
.where(eq(tickets.userId, userId)) | ||
.orderBy(desc(conferences.startDate)) | ||
|
||
return conferencesUserIsAttending.map(({ conference }) => ({ | ||
id: conference.id, | ||
name: conference.name, | ||
})) | ||
}, | ||
) |
Oops, something went wrong.