Skip to content

Commit

Permalink
feat: availability card component and display (#38)
Browse files Browse the repository at this point in the history
* created querying functions

* created AvailabilityCard component and added to general page

* changed styling and updates colors file to include new pomegranate color

* resolved ESLint errors

* added message for no availabilities

* updated to reflect new design and implemented content moving when menubar is expanded

* changed design for date range on availability card
  • Loading branch information
aidenm1 authored and rohin-444 committed Dec 7, 2024
1 parent fb08725 commit 682949c
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 10 deletions.
40 changes: 40 additions & 0 deletions api/supabase/queries/availability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,43 @@ export async function fetchAvailabilitiesByFacilityId(facility_id: UUID) {
return null; // Return null on unexpected error
}
}

export async function fetchAllAvailabilities() {
try {
const { data, error } = await supabase.from('availabilities').select('*');
if (error) {
throw new Error(error.message);
}
if (data && data.length == 0) {
console.log('No availabilities found');
return [];
}
return data;
} catch (error) {
console.error('An unexpected error occured:', error);
return null;
}
}

export async function fetchDatesByAvailabilityID(availability_id: UUID) {
try {
const { data, error } = await supabase
.from('available_dates')
.select('*')
.eq('availability_id', availability_id);
if (error) {
throw new Error(error.message);
}
if (data && data.length == 0) {
console.log(
'No dates found for this availability id or availability_id is undefined',
availability_id,
);
return [];
}
return data;
} catch (error) {
console.error('An unexpected error occured:', error);
return null;
}
}
2 changes: 1 addition & 1 deletion app/(auth)/auth-styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export const Input = styled.input`

export const Button = styled.button`
font-family: ${Sans.style.fontFamily};
background-color: ${COLORS.pomegranate};
background-color: ${COLORS.pomegranate12};
color: white;
font-size: 1rem;
padding: 0.75rem;
Expand Down
138 changes: 138 additions & 0 deletions app/availability/general/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
'use client';

import React, { useEffect, useState } from 'react';
import {
fetchAllAvailabilities,
fetchDatesByAvailabilityID,
} from '@/api/supabase/queries/availability';
import AvailabilityCard from '@/components/AvailabilityCard/AvailabilityCard';
import MenuBar from '@/components/MenuBar/MenuBar';
import Add from '@/public/images/add.svg';
import COLORS from '@/styles/colors';
import { H3 } from '@/styles/text';
import { Availabilities, AvailableDates } from '@/types/schema';
import * as styles from './styles';

type AvailabilitiesByYear = {
[year: string]: {
availability: Availabilities;
available_dates: AvailableDates[];
}[];
};

export default function AvailabilityPage() {
const [groupedByYear, setGroupedByYear] = useState<AvailabilitiesByYear>({});
const [isLoading, setIsLoading] = useState(true);
const [menuExpanded, setMenuExpanded] = useState(false); // Track the expanded state of the menu

useEffect(() => {
async function fetchAndGroupData() {
try {
// Step 1: Fetch all availabilities
const availabilities = await fetchAllAvailabilities();

if (!availabilities) {
return;
}

// Step 2: Group by year while fetching associated dates
const grouped: AvailabilitiesByYear = {};
for (const availability of availabilities) {
const availableDates = await fetchDatesByAvailabilityID(
availability.availability_id,
);

const year = availableDates?.[0]?.available_date
? new Date(availableDates[0].available_date)
.getFullYear()
.toString()
: null;

//don't display availability cards that have no availabilities associated
if (year == null) {
continue;
}

if (!grouped[year]) {
grouped[year] = [];
}

grouped[year].push({
availability,
available_dates: availableDates ?? [],
});
}
for (const year in grouped) {
grouped[year].sort((a, b) => {
const firstDateA = new Date(
a.available_dates[0]?.available_date ?? 0,
).getTime();
const firstDateB = new Date(
b.available_dates[0]?.available_date ?? 0,
).getTime();
return firstDateA - firstDateB;
});
}

setGroupedByYear(grouped);
setIsLoading(false); // Stop loading after data fetch
} catch (error) {
console.error('Error fetching data:', error);
}
}

fetchAndGroupData();
}, []);

return (
<div>
<MenuBar setMenuExpanded={setMenuExpanded} />{' '}
{/* Pass function to update state */}
<styles.Page $menuExpanded={menuExpanded}>
<styles.AllAvailabilitiesHolder>
<styles.TitleContainer>
<H3 $fontWeight="500" $color="#000" $align="left">
Availabilities
</H3>
<styles.AddImage src={Add} alt="add icon" />
</styles.TitleContainer>
{/* Check if there are no availabilities */}
{isLoading ? (
<styles.message
$fontWeight="400"
$color={COLORS.gray11}
$align="center"
>
Loading availabilities...
</styles.message>
) : Object.keys(groupedByYear).length === 0 ? (
<styles.message
$fontWeight="400"
$color={COLORS.gray11}
$align="center"
>
No availabilities yet,
<br />
add one with the plus sign!
</styles.message>
) : (
Object.entries(groupedByYear).map(([year, availabilities]) => (
<div key={year}>
<styles.YearText $fontWeight="500" $color="#000" $align="left">
{year}
</styles.YearText>
{availabilities.map(({ availability, available_dates }) => (
<AvailabilityCard
key={availability.availability_id}
availability={availability}
availableDates={available_dates}
/>
))}
</div>
))
)}
</styles.AllAvailabilitiesHolder>
</styles.Page>
</div>
);
}
45 changes: 45 additions & 0 deletions app/availability/general/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use client';

import NextImage from 'next/image';
import styled from 'styled-components';
import { H6, P } from '@/styles/text';

export const Page = styled.main<{ $menuExpanded: boolean }>`
display: flex;
min-width: 100%;
min-height: 100vh;
justify-content: center;
overflow: hidden;
margin-left: ${({ $menuExpanded }) =>
$menuExpanded ? '10%' : '0'}; /* Fixed margin for the expanded menu */
transition: margin-left 0.3s ease; /* Smooth transition */
`;

export const AllAvailabilitiesHolder = styled.main`
display: flex;
width: 28.75%;
flex-direction: column;
`;

export const TitleContainer = styled.main`
display: flex;
margin-top: 4.43rem;
margin-bottom: 2.62rem;
justify-content: space-between;
align-items: center;
width: 100%;
`;

export const YearText = styled(H6)`
margin-bottom: 1.5rem;
`;

export const AddImage = styled(NextImage)`
width: 1.5rem;
height: 1.5rem;
`;

export const message = styled(P)`
text-align: center;
margin-top: 5.75rem;
`;
7 changes: 6 additions & 1 deletion app/onboarding/finalize/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,13 @@ export const ContinueButton = styled.button`
justify-content: center;
align-items: center;
align-self: stretch;
<<<<<<< HEAD:app/onboarding/yay/styles.ts
border-radius: 99999px;
background: ${COLORS.pomegranate12};
=======
border-radius: 8px;
background: ${COLORS.pomegranate};
background: ${COLORS.pomegranate12};
>>>>>>> c33d5a0fb4596e1d2e004014b99e33e17cee93e9:app/onboarding/finalize/styles.ts
border-style: solid;
border-color: ${COLORS.gray12};
cursor: pointer;
Expand Down
4 changes: 2 additions & 2 deletions app/onboarding/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ export const Button = styled.button<{ disabled?: boolean }>`
width: 30%;
height: 2.75rem;
background-color: ${({ disabled }) =>
disabled ? COLORS.pomegranate10 : COLORS.pomegranate};
disabled ? COLORS.pomegranate10 : COLORS.pomegranate12};
border-color: ${({ disabled }) =>
disabled ? COLORS.pomegranate10 : COLORS.pomegranate};
disabled ? COLORS.pomegranate10 : COLORS.pomegranate12};
border-style: solid;
border-radius: 8px;
display: inline-flex;
Expand Down
86 changes: 86 additions & 0 deletions components/AvailabilityCard/AvailabilityCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';
import Arrow from '@/public/images/white_back.svg';
import COLORS from '@/styles/colors';
import { H5, P } from '@/styles/text';
import { Availabilities, AvailableDates } from '@/types/schema';
import * as styles from './styles';

interface AvailabilityCardProps {
availability: Availabilities;
availableDates: AvailableDates[];
}

export default function AvailabilityCard({
availability,
availableDates,
}: AvailabilityCardProps) {
const dateRange =
availableDates.length > 0
? {
earliest: new Date(
Math.min(
...availableDates.map(date =>
new Date(date.available_date).getTime(),
),
),
),
latest: new Date(
Math.max(
...availableDates.map(date =>
new Date(date.available_date).getTime(),
),
),
),
}
: null;

// Format the dates
let formattedRange = dateRange
? `${dateRange.earliest.toLocaleString('default', {
month: 'short',
day: 'numeric',
})} - ${dateRange.latest.toLocaleString('default', {
month: 'short',
day: 'numeric',
})}`
: 'No dates available';

if (dateRange && dateRange.earliest.getDate() == dateRange.latest.getDate()) {
formattedRange = `${dateRange.earliest.toLocaleString('default', {
month: 'short',
day: 'numeric',
})}`;
}

return (
<styles.AvailabilityContainer>
<styles.AvailabilityHeader>
<styles.AvailabilityTitle>
<H5 $fontWeight="500" $color={COLORS.bread1} $align="left">
{availability.name}
</H5>
<P $fontWeight="400" $color={COLORS.gray4} $align="left">
{formattedRange}
</P>
</styles.AvailabilityTitle>
<styles.Arrow src={Arrow} alt="arrow" />
</styles.AvailabilityHeader>
<styles.Content>
<div>
<styles.SubHeader>
<P $fontWeight="500" $color={COLORS.gray12} $align="left">
Description
</P>
<styles.TruncatedText
$fontWeight="400"
$color={COLORS.gray11}
$align="left"
>
{availability.additional_info}
</styles.TruncatedText>
</styles.SubHeader>
</div>
</styles.Content>
</styles.AvailabilityContainer>
);
}
Loading

0 comments on commit 682949c

Please sign in to comment.