Skip to content
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "server/server.js",
"type": "module",
"scripts": {
"start": "npm run reset && nodemon --require dotenv/config server.js",
"start": "npm run reset && nodemon --require dotenv/config server/server.js",
"reset": "cd server/config && node --require dotenv/config reset.js"
},
"repository": {
Expand Down
4 changes: 3 additions & 1 deletion server/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ PGDATABASE="flowerhunt"
PGHOST="dpg-d7ghkn57vvec739k76o0-a.oregon-postgres.render.com"
PGPASSWORD="uWb6kOYyJkBxrk2IkHsmvTR9ZZHd4ebW"
PGPORT="5432"
PGUSER="flowerhunt_user"
PGUSER="flowerhunt_user"

PLANT_API_KEY=your_key_here
172 changes: 172 additions & 0 deletions server/config/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { pool } from "./database.js";
import { fetchFlowersFromAPI } from "../services/plantAPI.js";



const flowerMeanings ={
"Abatina": "Fickleness",
"Acanthus": "The fine art, Artifice",
"Aloe": "Grief, Woe",
"Amaryllis": "Pride, pastorial poetry",
"Anemone": "Forsaken",
"Angelica": "Inspiration",
"Apple Blossom": "Preference",
"Arborvitae": "Unchanging friendship",
"Aster": "symbol of love, daintiness",
"Azalea": "Temperance, fragile passion, chinese symbol of womanhood",
"Baby's Breath": "Everlasting love",
"Bachelor's Button": "Single blessedness",
"Basil": "Good wishes, best wishes",
"Bay tree": "Glory",
"Begonia": "Beware",
"Belledonna":"Silence",
"Bells-of-Ireland": "Good luck",
"Bittersweet": "Truth",
"Black-eyed Susan": "Justice",
"Bluebell": "Humility",
"Borage" : "Bluntness",
"Butterfly weed": "Let me go",
"Cactus": "Endurance",
"Calla lily": "Magnificent beauty",
"Pink Camellia": "Longing",
"Red Camellia": "Passion",
"White Camellia": "Adoration",
"Candytuft": "Indifference",
"Carnation":"Fascination, women love",
"Pink Carnation": "I'll never forget you",
"Red Carnation": "Admiration, Deep love",
"purple Carnation": "Capriciousness",
"yellow Carnation": "Disappointment, rejection",
"White Carnation": "Pure love, good luck",
"Cattail": "Peace, prosperity",
"Chamomile": "Patience, rest",
"Chives": "Usefulness",
"Red Chrysanthemum": "I love you",
"White Chrysanthemum": "Loyal love",
"Yellow Chrysanthemum": "Slighted love",
"Clemantis": "Mental beauty",
"Cleome": "Elope with me",
"Clover": "Good luck",
"Columbine": "Foolishness, Folly",
"Coreopsis": "Always cheerful",
"Crocus": "Cheerfulness",
"Cyclamen": "Resignation and goodbye",
"Daffodil": "Unrequited love, regard",
"Daisy": "Innocence, loyal love, purity",
"Dandelion": "Happiness,faithfulness",
"Daylily": "Coquetry, Chinese symbol of motherhood",
"Edelweiss": "Devotion",
"Evening Primrose": "Inconstancy",
"Fennel": "Flattery",
"Fern": "Fasination, secret bond of love",
"Fir": "Time",
"Flax": "Domestic symbol",
"Forget-Me-Not": "True love, remembrance",
"Forsythia": "Anticipation",
"Gardenia": "Secret love",
"Garlic": "Strength, courage",
"Geranium": "Foolishness",
"Gladiolus": "Sincerity, victory",
"Gloxinia": "Love at first sight",
"Goldenrod": "Encouragement",
"Heliotrope": "Devotion, eternal love",
"Hibiscus": "Delicate beauty",
"Holly": "Defense, domestic happiness",
"Honeysuckle": "Generosity",
"Hyacinth": "Playfulness, rashness",
"Blue Hyacinth": "Constancy",
"Purple Hyacinth": "Sorrow",
"Yellow Hyacinth": "Jealousy",
"White Hyacinth": "Loveliness, prayers for someone",
"Hydrangea": "Frigidity and heartlessness",
"Hyssop": "Sacrifice, purification",
"Iris": "Faith, hope, wisdom",
"Ivy": "Fidelity",
"Jasmine": "Grace, elegance",
"Lady's Slipper": "Capricious beauty",
"Larkspur": "Levity, fickleness",
"Lilac": "Old love, joy of youth",
"Lily": "Purity, refined beauty",
"Lily of the Valley": "Return of happiness, Sweetness, humility",
"Lavender": "Distrust",
"lotus": "Enlightenment, rebirth",
"Magnolia": "Dignity, nobility",
"Marigold": "Despair and grief over a loved one",
"marjoram": "Happiness",
"Mint": "Virtue",
"Mistletoe": "Affection",
"Mock orange": "Deceit",
"Morning Glory": "Affection",
"Monkshood": "Caution",
"Moss": "Maternal love",
"Mugwort": "Happiness in love",
"Myrtle": "Love in marriage",
"Narcissus": "Egotism",
"Nasturtium": "Patriotism, victory in battle",
"oak": "Strength and endurance",
"Orchid": "Refinement, beauty, love",
"Pansy": "Thoughts",
"Peony": "Shame, bashfulness",
"Periwinkle": "Friendship",
"Petunia": "Resentment and anger",
"Pine":"Hope, humility, piety",
"Poppy": "Consolation, remembrance, eternal sleep",
"Primrose": "Young love",
"Rhododendron": "Danger",
"Rosebud": "Beauty, innocent love",
"Pink Rose": "Admiration, gratitude",
"Red Rose": "Love, passion",
"yellow Rose": "Decrease of love, jealousy, infidelity",
"White Rose": "Purity, innocence",
"Rosemary": "Remembrance",
"Sage": "Wisdom, immortality",
"Saffron": "Joy and happiness",
"Salvia": "Forever mine",
"Smilax": "Loveliness",
"Snapdragon": "Graciousness, deception",
"sorrel": "Affection",
"Sweet Pea": "Goodbye",
"Sweet William": "Gallantry",
"Tarragon": "Fascination",
"Tiger Lily": "Wealth and pride",
"Thistle": "Nobility of character",
"Thyme": "Courage, bravery",
"Tulip": "Perfect love",
"red Tulip": "Declaration of love",
"yellow Tulip": "Cheerful thoughts",
"White Tulip": "Forgiveness",
"Violet": "Modesty, faithfulness, watchfulness",
"Willow": "Sadness",
"Wisteria": "Welcome, blissful, devotion",
"Yarrow": "Everlasting love",
"Zinnia": "Thoughts of absent friends",
}

export const seedFlowers = async () => {
const flowers = await fetchFlowersFromAPI();
for (const flower of flowers) {
// const nameKey = flower.name?.toLowerCase().trim();
// const meaning = flowerMeanings[nameKey] ?? flower.flower_meaning;
const nameKey = flower.name?.toLowerCase().trim();
// Try exact match first, then partial match
const meaning =
flowerMeanings[nameKey] ??
Object.entries(flowerMeanings).find(([k]) => nameKey?.includes(k))?.[1] ??
flower.flower_meaning;

await pool.query(
`INSERT INTO flowers (name, description, flower_family, flower_meaning, image_url)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT DO NOTHING`,
[
flower.name,
flower.description,
flower.flower_family,
meaning, // <-- use the enriched meaning here
flower.image_url,
],
);
}

console.log(`Seeded ${flowers.length} flowers`);
};
86 changes: 86 additions & 0 deletions server/controllers/flowers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { pool } from "../config/database.js";

const getFlowers = async (req, res) => {
try {
const { meaning, family, search } = req.query;
let query = "SELECT * FROM flowers WHERE true";
const params = [];

if (meaning) {
params.push(`%${meaning}%`);
query += ` AND flower_meaning ILIKE $${params.length}`;
}
if (family) {
params.push(family);
query += ` AND flower_family = $${params.length}`;
}
if (search) {
params.push(`%${search}%`);
query += ` AND name ILIKE $${params.length}`;
}

const { rows } = await pool.query(query, params);
res.json(rows);
} catch (error) {
res.status(500).json({ error: error.message });
}
};

const getFlowerById = async (req, res) => {
try {
const { rows } = await pool.query(
"SELECT * FROM flowers WHERE id = $1",
[req.params.id]
);
if (!rows.length) return res.status(404).json({ error: "Flower not found" });
res.json(rows[0]);
} catch (error) {
res.status(500).json({ error: error.message });
}
};

const createFlower = async (req, res) => {
try {
const { name, description, flower_family, flower_meaning, image_url } = req.body;
const { rows } = await pool.query(
`INSERT INTO flowers (name, description, flower_family, flower_meaning, image_url)
VALUES ($1,$2,$3,$4,$5) RETURNING *`,
[name, description, flower_family, flower_meaning, image_url]
);
res.status(201).json(rows[0]);
} catch (error) {
res.status(500).json({ error: error.message });
}
};

const updateFlower = async (req, res) => {
try {
const { name, description, flower_family, flower_meaning, image_url } = req.body;
const { rows } = await pool.query(
`UPDATE flowers SET name=$1, description=$2, flower_family=$3,
flower_meaning=$4, image_url=$5 WHERE id=$6 RETURNING *`,
[name, description, flower_family, flower_meaning, image_url, req.params.id]
);
if (!rows.length) return res.status(404).json({ error: "Flower not found" });
res.json(rows[0]);
} catch (error) {
res.status(500).json({ error: error.message });
}
};

const deleteFlower = async (req, res) => {
try {
await pool.query("DELETE FROM flowers WHERE id = $1", [req.params.id]);
res.status(204).send();
} catch (error) {
res.status(500).json({ error: error.message });
}
};

export default {
getFlowers,
getFlowerById,
createFlower,
updateFlower,
deleteFlower,
};
18 changes: 18 additions & 0 deletions server/routes/flowers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Router } from "express";
import {
getFlowers,
getFlowerById,
createFlower,
updateFlower,
deleteFlower,
} from "../controllers/flowers.js";

const router = Router();

router.get("/", getFlowers);
router.get("/:id", getFlowerById);
router.post("/", createFlower);
router.patch("/:id", updateFlower);
router.delete("/:id", deleteFlower);

export default router;
21 changes: 15 additions & 6 deletions server/server.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import express from "express";
import cors from "cors";
import flowerRoutes from "./routes/flowers.js";

const app = express();

app.use(express.json());
app.use(cors());

app.get("/", (req, res) => {
res
.status(200)
.send(
'<h1 style="text-align: center; margin-top: 50px;">🌸FlowerHunt API</h1>',
);
app.use("/api/flowers", flowerRoutes);

app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: "Something went wrong" });
});


// app.get("/", (req, res) => {
// res
// .status(200)
// .send(
// '<h1 style="text-align: center; margin-top: 50px;">🌸FlowerHunt API</h1>',
// );
// });

const PORT = process.env.PORT || 3001;

app.listen(PORT, () => {
Expand Down
17 changes: 17 additions & 0 deletions server/services/plantAPI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Fetches flowers from external API and maps them to your DB schema
const API_BASE = "..."; // or your chosen API

export const fetchFlowersFromAPI = async (page = 1) => {
const res = await fetch(
`${API_BASE}/species-list?key=${process.env.PLANT_API_KEY}&page=${page}&type=flower`,
);
const json = await res.json();

return json.data.map((plant) => ({
name: plant.common_name,
description: plant.description ?? null,
flower_family: plant.family ?? null,
flower_meaning: null, // most APIs don't have this; you'll add manually or skip
image_url: plant.default_image?.regular_url ?? null,
}));
};