Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Implement Plant Seasonality Filters #17

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/supabase/queries/plantSeasonality.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ export async function getPlantSeasonality(
input_state: string,
): Promise<Plant[]> {
const { data, error } = await supabase
.from('plant_seasonality')
.from('plants')
.select('*')
.eq('state', input_state);
.eq('us_state', input_state);
if (error)
throw new Error(`Error fetching plant seasonality: ${error.message}`);
return data;
Expand Down
21 changes: 21 additions & 0 deletions api/supabase/queries/plants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { UUID } from 'crypto';
import { Plant } from '@/types/schema';
import supabase from '../createClient';

export async function getAllPlants(): Promise<Plant[]> {
const { data, error } = await supabase.from('plants').select('*');
if (error) throw new Error(`Error fetching all plants: ${error.message}`);
return data;
}

export async function getPlantById(plantId: UUID): Promise<Plant> {
const { data, error } = await supabase
.from('plants')
.select('*')
.eq('id', plantId);
if (error) {
throw new Error(`Error getting matching plant: ${error.message}`);
}

return data[0];
}
68 changes: 68 additions & 0 deletions app/seasonal-planting-guide/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use client';

import React, { useState } from 'react';
import FilterDropdown from '@/components/FilterDropdown';
import { PlantList } from '@/components/PlantList';

const SeasonalPlantingGuide = () => {
const growingSeasonOptions = ['Spring', 'Summer', 'Fall', 'Winter'];
const harvestSeasonOptions = ['Spring', 'Summer', 'Fall', 'Winter'];
const plantingTypeOptions = [
'Start Seeds Indoors',
'Start Seeds Outdoors',
'Plant Seedlings/Transplant Outdoors',
];

const [selectedGrowingSeason, setSelectedGrowingSeason] =
useState<string>('');
const [selectedHarvestSeason, setSelectedHarvestSeason] =
useState<string>('');
const [selectedPlantingType, setSelectedPlantingType] = useState<string>('');

const clearFilters = () => {
setSelectedGrowingSeason('');
setSelectedHarvestSeason('');
setSelectedPlantingType('');
};

return (
<div>
<FilterDropdown
name="growingSeason"
id="growingSeason"
value={selectedGrowingSeason}
setStateAction={setSelectedGrowingSeason}
options={growingSeasonOptions}
placeholder="Growing Season"
/>

<FilterDropdown
name="harvestSeason"
id="harvestSeason"
value={selectedHarvestSeason}
setStateAction={setSelectedHarvestSeason}
options={harvestSeasonOptions}
placeholder="Harvest Season"
/>

<FilterDropdown
name="plantingType"
id="plantingType"
value={selectedPlantingType}
setStateAction={setSelectedPlantingType}
options={plantingTypeOptions}
placeholder="Planting Type"
/>

<button onClick={clearFilters}>Clear filters</button>

<PlantList
growingSeasonFilterValue={selectedGrowingSeason}
harvestSeasonFilterValue={selectedHarvestSeason}
plantingTypeFilterValue={selectedPlantingType}
/>
</div>
);
};

export default SeasonalPlantingGuide;
25 changes: 25 additions & 0 deletions app/view-plants/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client';

import { useEffect, useState } from 'react';
import { UUID } from 'crypto';
import { getPlantById } from '@/api/supabase/queries/plants';
import PlantCard from '@/components/PlantCard/PlantCard';
import { Plant } from '@/types/schema';

export default function Home() {
const [result, setResult] = useState<Plant>();
useEffect(() => {
const getData = async () => {
const testUUID: UUID = '010ae695-6cc8-4af4-919a-d15b92fdd68d';
const plant2 = await getPlantById(testUUID);
setResult(plant2); // Set the result to state
};

getData(); // Call the async function when the component mounts
}, []);
if (result === undefined) {
return <div>Loading...</div>;
} else {
return <PlantCard plant={result} />;
}
}
51 changes: 51 additions & 0 deletions components/FilterDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { useState } from 'react';

interface FilterDropdownProps {
name: string;
id: string;
value: string;
setStateAction: React.Dispatch<React.SetStateAction<string>>;
options: string[];
placeholder: string;
}

export default function FilterDropdown({
name,
id,
value,
setStateAction,
options,
placeholder,
}: FilterDropdownProps) {
const [isOpen, setIsOpen] = useState(false);

const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
setStateAction(event.target.value);
setIsOpen(false);
};

const handleToggle = () => {
setIsOpen(!isOpen);
};

return (
<select
name={name}
id={id}
onChange={handleChange}
onClick={handleToggle}
onBlur={() => setIsOpen(false)}
value={value}
>
{/*Default placeholder text*/}
<option value="" disabled hidden>
{placeholder}
</option>
{options.map((option, index) => (
<option key={index} value={option}>
{option}
</option>
))}
</select>
);
}
36 changes: 36 additions & 0 deletions components/PlantCard/PlantCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import { Plant } from '@/types/schema';
import styles from './PlantCardStyles.module.css';

export default function PlantCard({ plant }: { plant: Plant }) {
return (
<div className={styles.Card}>
<div className={styles.CardPic}>
<img alt={plant.plant_name}></img>

Check warning on line 9 in components/PlantCard/PlantCard.tsx

View workflow job for this annotation

GitHub Actions / Run ESLint, Prettier, and TypeScript compiler

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
</div>
<div className={styles.CardContent}>
<h2>{plant.plant_name}</h2>
<div className={styles.PlantAttributes}>
<div className={styles.Attribute}>
{/* icon */}
<p>{plant.harvest_start + ' - ' + plant.harvest_end}</p>

Check warning on line 16 in components/PlantCard/PlantCard.tsx

View workflow job for this annotation

GitHub Actions / Run ESLint, Prettier, and TypeScript compiler

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
</div>
<div className={styles.Attribute}>
{/* icon */}
<p>{plant.water_frequency}</p>
</div>
<div className={styles.Attribute}>
{/* icon */}
<p>
{plant.sunlight_min_hours}
{plant.sunlight_max_hours
? ' - ' + plant.sunlight_max_hours
: ''}{' '}
hours/day
</p>
</div>
</div>
</div>
</div>
);
}
52 changes: 52 additions & 0 deletions components/PlantCard/PlantCardStyles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.Card {
height: 40vh;
width: 20vw;
display: flex;
flex-direction: column;
align-items: start;
border-radius: 12px;
background-color: white;
box-shadow:
0 24px 38px 3px rgba(0, 0, 0, 0.14),
0 9px 46px 8px rgba(0, 0, 0, 0.12),
0 11px 15px -7px rgba(0, 0, 0, 0.2);
}

.CardPic {
height: 60%;
width: 100%;
background-color: #f5f6f6;
display: flex;
justify-content: center;
align-items: center;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
}
.CardContent {
display: flex;
flex-direction: column;
padding-left: 1vw;
height: 40%;
row-gap: 1vh;
}
.CardContent > * {
margin: 0;
}
.CardContent > h2 {
font-size: 1.5vw;
margin-top: 1vh;
}
.PlantAttributes {
display: flex;
flex-direction: column;
gap: 1vh;
}

.Attribute {
display: flex;
flex-direction: row;
}
.Attribute > * {
margin: 0;
font-size: 1vw;
}
Loading