Skip to content

Commit

Permalink
Merge pull request #75 from opportunity-hack/dev
Browse files Browse the repository at this point in the history
Bugfixes
  • Loading branch information
gregv authored Dec 29, 2023
2 parents a99d1b2 + 0d56cdf commit 6e66832
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 40 deletions.
62 changes: 62 additions & 0 deletions app/components/EventAgenda.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useUser } from '~/utils/user.ts'
import { volunteerTypes, type EventWithVolunteers } from '~/data.ts'

type VolunteerTypes = typeof volunteerTypes
type VolunteerType = VolunteerTypes[number]

interface PositionStatusProps {
event: EventWithVolunteers
volunteerType: VolunteerType
}

function PositionStatus({ volunteerType, event }: PositionStatusProps) {
const user = useUser()

const positionFilled =
event[volunteerType.field].length >= event[volunteerType.reqField]
const containerClass = `grid grid-cols-2 gap-4 ${
positionFilled ? 'text-muted-foreground' : ''
}`

const userIsRegistered = event[volunteerType.field]
.map(user => user.id)
.includes(user.id)
const volunteerTypeClass = `capitalize ${
userIsRegistered ? 'before:content-["✅"] before:pr-1' : ''
}`

const spotsLeft =
event[volunteerType.reqField] - event[volunteerType.field].length

if (event[volunteerType.reqField] > 0)
return (
<div className={containerClass}>
<div className={volunteerTypeClass}>{volunteerType.displayName}</div>
<div className="whitespace-nowrap">
{spotsLeft} spot{spotsLeft === 1 ? '' : 's'} left
</div>
</div>
)
}

export function EventAgenda({ event }: { event: EventWithVolunteers }) {
const eventIsUpcoming = event.end.valueOf() > new Date().valueOf()

return (
<div className="flex min-w-[25rem] gap-4">
<div className="shrink-0 grow basis-40">{event.title}</div>
<div className="flex shrink-0 grow basis-72 flex-col text-sm">
<div className="max-w-sm">
{eventIsUpcoming &&
volunteerTypes.map(volunteerType => (
<PositionStatus
key={volunteerType.field}
volunteerType={volunteerType}
event={event}
/>
))}
</div>
</div>
</div>
)
}
33 changes: 18 additions & 15 deletions app/routes/_marketing+/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export default function Index() {
/>
<div className="absolute inset-0 bg-[color:rgba(27,167,254,0.5)] mix-blend-multiply" />
</div>
<div className="relative flex flex-col items-center px-4 pb-8 pt-8 sm:px-6 sm:pb-14 sm:pt-16 lg:pt-18 lg:px-8 lg:pb-20">
<h1 className="text-center font-extrabold tracking-tight text-5xl sm:text-8xl lg:text-9xl">
<div className="lg:pt-18 relative flex flex-col items-center px-4 pb-8 pt-8 sm:px-6 sm:pb-14 sm:pt-16 lg:px-8 lg:pb-20">
<h1 className="text-center text-5xl font-extrabold tracking-tight sm:text-8xl lg:text-9xl">
<a
className="block uppercase text-brand-secondary drop-shadow-md"
href="https://www.thebarnaz.com"
Expand Down Expand Up @@ -57,19 +57,22 @@ export default function Index() {

<div className="mx-auto mt-8 max-w-7xl px-4 py-2 sm:px-6 lg:px-8">
<div className="flex flex-col flex-wrap items-center justify-center gap-8 rounded-3xl bg-slate-100 py-4 dark:bg-slate-200">

<div className="text-black"><b><a href="https://trottrack.org">Trot Track</a></b> is built by:
<a
key="ohack.dev"
href="http://ohack.dev"
className="flex h-24 justify-center p-1 grayscale transition hover:grayscale-0 focus:grayscale-0"
>
<img
alt="opportunity hack logo"
src={ohack}
className="object-contain mt-0 mb-0"
/>
</a>
<div className="text-center text-black">
<b>
<a href="https://trottrack.org">Trot Track</a>
</b>{' '}
is built by:
<a
key="ohack.dev"
href="http://ohack.dev"
className="flex h-24 justify-center p-1 grayscale transition hover:grayscale-0 focus:grayscale-0"
>
<img
alt="opportunity hack logo"
src={ohack}
className="mb-0 mt-0 object-contain"
/>
</a>
</div>
</div>
</div>
Expand Down
56 changes: 36 additions & 20 deletions app/routes/calendar+/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
type HorseData,
type EventWithVolunteers,
} from '~/data.ts'
import { useState } from 'react'
import { useMemo, useState } from 'react'

import { prisma } from '~/utils/db.server.ts'
import { requireUserId } from '~/utils/auth.server.ts'
Expand Down Expand Up @@ -71,6 +71,7 @@ import {
horseDateConflicts,
renderHorseConflictMessage,
} from '~/utils/cooldown-functions.ts'
import { EventAgenda } from '~/components/EventAgenda.tsx'

const locales = {
'en-US': enUS,
Expand Down Expand Up @@ -139,8 +140,12 @@ const instructorSchema = z

const createEventSchema = z.object({
title: z.string().min(1, 'Title is required'),
dates: z.string().regex(new RegExp(/^(\d{4}-\d{2}-\d{2},?\s?)+$/g), 'Invalid dates'),
startTime: z.string().regex(new RegExp(/^\d{2}:\d{2}$/g), 'Invalid start time'),
dates: z
.string()
.regex(new RegExp(/^(\d{4}-\d{2}-\d{2},?\s?)+$/g), 'Invalid dates'),
startTime: z
.string()
.regex(new RegExp(/^\d{2}:\d{2}$/g), 'Invalid start time'),
duration: z.coerce.number().gt(0),
horses: z.array(horseSchema).optional(),
instructor: instructorSchema,
Expand Down Expand Up @@ -269,13 +274,13 @@ export default function Schedule() {

const [filterFlag, setFilterFlag] = useState(false)


const eventsThatNeedHelp = events.filter((event: (typeof events)[number]) => {
return (
event.cleaningCrewReq > event.cleaningCrew.length ||
event.lessonAssistantsReq > event.lessonAssistants.length ||
event.horseLeadersReq > event.horseLeaders.length ||
event.sideWalkersReq > event.sideWalkers.length
event.start.valueOf() > new Date().valueOf() &&
(event.cleaningCrewReq > event.cleaningCrew.length ||
event.lessonAssistantsReq > event.lessonAssistants.length ||
event.horseLeadersReq > event.horseLeaders.length ||
event.sideWalkersReq > event.sideWalkers.length)
)
})

Expand All @@ -284,10 +289,19 @@ export default function Schedule() {
setRegisterOpen(!registerOpen)
}

const components = useMemo(
() => ({
agenda: {
event: EventAgenda,
},
}),
[],
)

return (
<div className="grid place-items-center gap-2">
<h1 className="mb-3 text-5xl">Calendar</h1>
<div className="flex gap-2 mb-0">
<h1 className="mb-3 text-5xl">Calendar</h1>
<div className="mb-0 flex gap-2">
<Checkbox
checked={filterFlag}
onCheckedChange={() => setFilterFlag(!filterFlag)}
Expand All @@ -297,38 +311,40 @@ export default function Schedule() {
Show only events that need more volunteers
</Label>
</div>

{userIsAdmin ? (
<CreateEventDialog horses={horses} instructors={instructors} />
) : null}
<CreateEventDialog horses={horses} instructors={instructors} />
) : null}

<div className="h-screen w-full flex justify-center">
<div className="flex h-screen w-full justify-center">
<Calendar
localizer={localizer}
events={filterFlag ? eventsThatNeedHelp : events}
tooltipAccessor={event => `Cleaning Crew: ${event.cleaningCrew.length} / ${event.cleaningCrewReq}\nSidewalkers: ${event.sideWalkers.length} / ${event.sideWalkersReq}\nLesson Assistants: ${event.lessonAssistants.length} / ${event.lessonAssistantsReq}\nHorse Leaders: ${event.horseLeaders.length} / ${event.horseLeadersReq}`}
tooltipAccessor={event =>
`Cleaning Crew: ${event.cleaningCrew.length} / ${event.cleaningCrewReq}\nSidewalkers: ${event.sideWalkers.length} / ${event.sideWalkersReq}\nLesson Assistants: ${event.lessonAssistants.length} / ${event.lessonAssistantsReq}\nHorse Leaders: ${event.horseLeaders.length} / ${event.horseLeadersReq}`
}
startAccessor="start"
endAccessor="end"
onSelectEvent={handleSelectEvent}
style={{
style={{
height: '95%',
width: '95%',
backgroundColor: 'white',
color: 'black',
padding: 20,
borderRadius: '1.5rem',
}}
components={components}
defaultView="agenda"
/>
</div>

<Dialog open={registerOpen} onOpenChange={setRegisterOpen}>
<RegistrationDialogue
selectedEventId={selectedEvent?.id}
events={events}
/>
</Dialog>


</div>
)
}
Expand Down Expand Up @@ -557,7 +573,7 @@ function CreateEventDialog({ horses, instructors }: CreateEventDialogProps) {
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button className="mt-0 mb-1" style={{ backgroundColor: '#58d5fe' }}>
<Button className="mb-1 mt-0" style={{ backgroundColor: '#58d5fe' }}>
<Icon className="text-body-md" name="plus">
Create New Event
</Icon>
Expand Down
8 changes: 6 additions & 2 deletions app/routes/settings+/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,12 @@ const profileFormSchema = z.object({
mailingList: checkboxSchema(),
birthdate: optionalDateTimeZoneSchema,
phone: phoneSchema,
height: z.coerce.number().min(0).optional(),
yearsOfExperience: z.coerce.number().min(0).optional(),
height: z.coerce
.number()
.int({ message: 'Height must be an integer in inches' })
.min(0)
.optional(),
yearsOfExperience: z.coerce.number().int().min(0).optional(),
currentPassword: z
.union([passwordSchema, z.string().min(0).max(0)])
.optional(),
Expand Down
1 change: 0 additions & 1 deletion app/routes/users+/$username.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export default function UsernameIndex() {
if (data.user.birthdate) {
age = differenceInYears(new Date(), data.user.birthdate)
}
console.log(age)

return (
<div className="container mx-auto mb-48 mt-36 flex flex-col items-center justify-center">
Expand Down
6 changes: 4 additions & 2 deletions app/utils/user-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ export const emailSchema = z

export const phoneSchema = z
.string()
.regex(/\(?\d{3}\)?\s?-?\d{3}-?\d{4}/, { message: 'Phone number must be ten digits'})
.transform(phone => phone.replaceAll(/\D/g, ''))
.regex(/^\(?\d{3}\)?\s?-?\d{3}-?\d{4}$/, {
message: 'Phone number must be ten digits',
})
.transform(phone => phone.replaceAll(/\D/g, ''))

0 comments on commit 6e66832

Please sign in to comment.