Skip to content

Commit

Permalink
Rebase with main
Browse files Browse the repository at this point in the history
  • Loading branch information
matherg committed Oct 17, 2023
1 parent ea436b3 commit 5b03e8c
Show file tree
Hide file tree
Showing 11 changed files with 930 additions and 29 deletions.
554 changes: 536 additions & 18 deletions client/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.16.0",
"react-select": "^5.7.7",
"ts-node": "^10.9.1"
},
"devDependencies": {
Expand Down
20 changes: 9 additions & 11 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@

import {
BrowserRouter as Router,
Route,
Routes,
} from 'react-router-dom';
import HomePage from './pages/HomePage';
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import HomePage from "./pages/HomePage";
import RequestsPage from "./pages/RequestsPage";

function App() {
return (
<Router>
<Routes>
<Route path = '/' element={<HomePage/>} />
</Routes>
</Router>
<Router>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/requests/" element={<RequestsPage />} />
</Routes>
</Router>
);
}

Expand Down
29 changes: 29 additions & 0 deletions client/src/components/CollectionSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useState } from "react";
import Select from "react-select";

const options = [
{ value: "Taylor's gifts", label: "Taylor's gifts" },
{ value: "Harry's gifts", label: "Harry's gifts" },
];

export type SelectValueType = {
[key: string]: string;
} | null;

export default function CollectionSelector() {
const [selectedOption, setSelectedOption] = useState<SelectValueType>(null);

const handleOption = (selection: SelectValueType) => {
setSelectedOption(selection);
};

return (
<div className="App">
<Select
defaultValue={selectedOption}
onChange={handleOption}
options={options}
/>
</div>
);
}
15 changes: 15 additions & 0 deletions client/src/components/Gift.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import { Gift } from "../types";

const Gift: React.FC<Gift> = ({ Name, Link }: Gift) => {
return (
<div>
<p className="">{Name}</p>
<a className="text-blue-800" href={Link} target="_blank" rel="noreferrer">
View product
</a>
</div>
);
};

export default Gift;
51 changes: 51 additions & 0 deletions client/src/components/RequestCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { useState } from "react";
import ResponseCard from "./ResponseCard";
import ResponseForm from "./ResponseForm";
import { GiftRequest } from "../types";

const RequestCard: React.FC<GiftRequest> = ({
RecipientName,
RecipientAge,
RecipientInterests,
BudgetMin,
BudgetMax,
GiftResponse,
DateNeeded,
}: GiftRequest) => {
const [showForm, setShowForm] = useState(false);

return (
<div className="flex flex-col w-full">
<h2 className="font-bold text-lg">
{RecipientName} ({DateNeeded.toDateString()})
</h2>
<div key={RecipientName} className="px-4 py-2 bg-slate-100">
<p>Recipient: {RecipientName}</p>
{!GiftResponse && (
<div>
<p>Recipient age: {RecipientAge}</p>
<p>Recipient interests: {RecipientInterests.join(", ")}</p>
<p>
Budget: ${BudgetMin} - ${BudgetMax}
</p>
<p>Needed by: {DateNeeded.toDateString()}</p>
</div>
)}
</div>
<div>
{GiftResponse && <ResponseCard {...GiftResponse} />}
{!GiftResponse && !showForm && (
<button
className="bg-blue-600 px-4 py-2 text-white rounded-md mt-4"
onClick={() => setShowForm(true)}
>
Add response
</button>
)}
{showForm && <ResponseForm />}
</div>
</div>
);
};

export default RequestCard
26 changes: 26 additions & 0 deletions client/src/components/ResponseCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from "react";
import Gift from "./Gift";
import { GiftResponse } from "../types";

const ResponseCard: React.FC<GiftResponse> = ({
GiftCollection,
CustomMessage,
}: GiftResponse) => {
return (
<div className="flex flex-col bg-slate-100 px-4 py-2">
<h2 className="font-bold text-md">Response:</h2>
<p>{CustomMessage}</p>
<div>
{GiftCollection.Gifts.map((gift) => {
return (
<div className="mt-2">
<Gift {...gift} />
</div>
);
})}
</div>
</div>
);
};

export default ResponseCard;
27 changes: 27 additions & 0 deletions client/src/components/ResponseForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import CollectionSelector from "./CollectionSelector";

const ResponseForm = () => {
return (
<div className="flex flex-col justify-between h-full mt-4">
<div>
<label className="block text-gray-700 text-sm font-bold mb-2">
Select a gift collection:
<CollectionSelector />
</label>
<label className="block text-gray-700 text-sm font-bold mb-2">
Custom message:
<input
className="border rounded w-full py-2 px-3 text-gray-700"
name="message"
type="text"
/>
</label>
</div>
<button className="bg-blue-600 ml-8 px-4 py-2 h-10 text-white rounded-md self-end">
Submit
</button>
</div>
);
};

export default ResponseForm;
54 changes: 54 additions & 0 deletions client/src/pages/RequestsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import RequestCard from "../components/RequestCard";
import { completeRequests, incompleteRequests } from "./mockData";
import { useState } from "react";
import Select from "react-select";

export type SelectValueType = {
[key: string]: string;
} | null;

const options = [
{ value: "0", label: "Incomplete requests" },
{ value: "1", label: "Complete requests" },
{ value: "2", label: "All requests" },
];

export default function RequestsPage() {
const [selectedOption, setSelectedOption] = useState<SelectValueType>({
value: "2",
label: "All requests",
});

const handleOption = (selection: SelectValueType) => {
setSelectedOption(selection);
};
return (
<div className="flex flex-col px-96 py-8">
<h2 className="font-bold text-xl">View gift requests</h2>
<p>Filter gift requests using the dropdown below. </p>
<Select
defaultValue={selectedOption}
onChange={handleOption}
options={options}
/>
{(selectedOption?.value == "0" || selectedOption?.value == "2") && (
<div className="mt-6">
<h2 className="font-bold text-xl text-blue-800">
Incomplete requests
</h2>
{incompleteRequests.map((req) => {
return <RequestCard {...req} />;
})}
</div>
)}
{(selectedOption?.value == "1" || selectedOption?.value == "2") && (
<div className="mt-6">
<h2 className="font-bold text-xl text-blue-800">Complete requests</h2>
{completeRequests.map((req) => {
return <RequestCard {...req} />;
})}
</div>
)}
</div>
);
}
133 changes: 133 additions & 0 deletions client/src/pages/mockData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { GiftRequest } from "../types";

export const completeRequests: GiftRequest[] = [
{
CustomerId: 1,
GiftResponseId: null,
RecipientName: "Alice",
RecipientAge: 25,
Occasion: ["Birthday", "Anniversary"],
RecipientInterests: ["Reading", "Traveling"],
BudgetMax: 100,
BudgetMin: 50,
GiftResponse: {
GiftCollection: {
CustomerId: 1,
Customer: { UserId: 1 },
CollectionName: "Books",
Gifts: [
{
Name: "The Catcher in the Rye",
Price: 20,
Link: "https://book-link",
Description: "Classic novel",
Demographic: "Adult",
GiftCollections: [],
},
{
Name: "To Kill a Mockingbird",
Price: 15,
Link: "https://book-link",
Description: "Classic novel",
Demographic: "Adult",
GiftCollections: [],
},
],
},
GiftCollectionId: 1,
CustomMessage: "Happy Birthday!",
},
DateNeeded: new Date("2023-01-15"),
},
{
CustomerId: 2,
GiftResponseId: null,
RecipientName: "Bob",
RecipientAge: 30,
Occasion: ["Christmas"],
RecipientInterests: ["Music", "Sports"],
BudgetMax: 150,
BudgetMin: 100,
GiftResponse: {
GiftCollection: {
CustomerId: 2,
Customer: { UserId: 2 },
CollectionName: "Tech Gadgets",
Gifts: [
{
Name: "Wireless Headphones",
Price: 80,
Link: "https://headphones-link",
Description: "High-quality sound",
Demographic: "Adult",
GiftCollections: [],
},
{
Name: "Smartwatch",
Price: 120,
Link: "https://smartwatch-link",
Description: "Fitness tracking and notifications",
Demographic: "Adult",
GiftCollections: [],
},
],
},
GiftCollectionId: 2,
CustomMessage: "Merry Christmas!",
},
DateNeeded: new Date("2023-12-25"),
},
{
CustomerId: 3,
GiftResponseId: null,
RecipientName: "Charlie",
RecipientAge: 22,
Occasion: ["Graduation"],
RecipientInterests: ["Art", "Movies"],
BudgetMax: 80,
BudgetMin: 50,
GiftResponse: {
GiftCollection: {
CustomerId: 3,
Customer: { UserId: 3 },
CollectionName: "Art Supplies",
Gifts: [
{
Name: "Acrylic Paint Set",
Price: 30,
Link: "https://paint-set-link",
Description: "High-quality pigments",
Demographic: "Young Adult",
GiftCollections: [],
},
{
Name: "Sketchbook",
Price: 20,
Link: "https://sketchbook-link",
Description: "Blank pages for creative ideas",
Demographic: "Young Adult",
GiftCollections: [],
},
],
},
GiftCollectionId: 3,
CustomMessage: "Congratulations on your graduation!",
},
DateNeeded: new Date("2023-05-20"),
},
];

export const incompleteRequests: GiftRequest[] = [
{
CustomerId: 3,
GiftResponseId: null,
RecipientName: "Charlie",
RecipientAge: 22,
Occasion: ["Graduation"],
RecipientInterests: ["Art", "Movies"],
BudgetMax: 80,
BudgetMin: 50,
GiftResponse: null,
DateNeeded: new Date("2023-05-20"),
},
];
Loading

0 comments on commit 5b03e8c

Please sign in to comment.