-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
1,409 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,3 +22,5 @@ dist-ssr | |
*.njsproj | ||
*.sln | ||
*.sw? | ||
|
||
/node_modules/ |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { FC, MouseEventHandler } from "react" | ||
|
||
interface ButtonProps { | ||
text: string | ||
type: "button" | "submit" | "reset" | undefined | ||
variant?: string | ||
onClick?: MouseEventHandler<HTMLButtonElement> | undefined | ||
} | ||
|
||
const Button: FC<ButtonProps> = ({ text, type, variant, onClick }) => { | ||
return ( | ||
<button | ||
type={type} | ||
onClick={onClick} | ||
className={` | ||
flex justify-center align-center transition duration-200 ease-linear hover:opacity-80 rounded-md px-12 py-3 min-w-full sm:min-w-max | ||
${variant === "primary" ? "text-title bg-primary" : "text-white bg-accent"} | ||
`} | ||
> | ||
{text} | ||
</button> | ||
) | ||
} | ||
|
||
export default Button |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { FC } from "react" | ||
import dogIcon from "../../assets/dogIcon.svg" | ||
import locationIcon from "../../assets/locationIcon.svg" | ||
import { Dog } from "../utils/requests/types" | ||
|
||
interface CardProps { | ||
dog: Dog | ||
selected: string[] | ||
setSelectedDogs: React.Dispatch<React.SetStateAction<string[]>> | ||
} | ||
|
||
const Card: FC<CardProps> = ({ dog, selected, setSelectedDogs }) => { | ||
const handleSelect = (id: string) => { | ||
if (selected.includes(id)) { | ||
setSelectedDogs((prevSelectedDogs) => | ||
prevSelectedDogs.filter((dogId) => dogId !== id) | ||
) | ||
} else { | ||
setSelectedDogs((prevSelectedDogs) => [...prevSelectedDogs, id]) | ||
} | ||
} | ||
|
||
return ( | ||
<button | ||
onClick={() => handleSelect(dog.id)} | ||
className={` | ||
p-4 flex flex-col gap-3 shadow-md bg-white rounded-lg cursor-pointer lg:flex-row border-2 border-solid border-transparent ${ | ||
selected.includes(dog.id) && "active-card" | ||
} | ||
`} | ||
> | ||
<img | ||
className="w-[100%] aspect-square object-cover rounded-sm md:rounded-md lg:w-2/5 lg:self-center" | ||
src={dog.img} | ||
alt="dog photo" | ||
/> | ||
<div className="w-full flex flex-col gap-2"> | ||
<p className="card-font "> | ||
{dog.name}, {dog.age} | ||
</p> | ||
|
||
<div className="card-grid gap-1"> | ||
<img className="sm:w-6 " src={dogIcon} alt="Dog icon" /> | ||
<p className="card-font whitespace-nowrap text-ellipsis overflow-hidden"> | ||
{dog.breed} | ||
</p> | ||
</div> | ||
<div className="flex gap-1"> | ||
<img className="sm:w-6" src={locationIcon} alt="Location icon" /> | ||
<p className="card-font">{dog.zip_code}</p> | ||
</div> | ||
</div> | ||
</button> | ||
) | ||
} | ||
|
||
export default Card |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { FC, useEffect, useState } from "react" | ||
import Select, { | ||
ActionMeta, | ||
CSSObjectWithLabel, | ||
GroupBase, | ||
MultiValue, | ||
OptionProps, | ||
} from "react-select" | ||
import api from "../utils/requests/api" | ||
import { StylesConfig } from "react-select" | ||
|
||
interface CustomSelectProps { | ||
setSelectedBreeds: React.Dispatch<React.SetStateAction<string[]>> | ||
} | ||
|
||
const CustomSelect: FC<CustomSelectProps> = ({ setSelectedBreeds }) => { | ||
// Select options for react-select | ||
const [selectOptions, setSelectOptions] = useState< | ||
{ value: String; label: String }[] | ||
>([]) | ||
|
||
// Styles for react-select | ||
const customStyles: StylesConfig<any> = { | ||
control: (base: CSSObjectWithLabel) => ({ | ||
...base, | ||
padding: [12, 10], | ||
fontSize: 16, | ||
outline: "none", | ||
background: "#ffffff", | ||
height: "100%", | ||
minWidth: "250px", | ||
borderWidth: "2px", | ||
borderColor: "rgb(209 213 219)", | ||
borderStyle: "solid", | ||
borderRadius: 6, | ||
}), | ||
option: ( | ||
base: CSSObjectWithLabel, | ||
{ isFocused }: OptionProps<any, boolean, GroupBase<any>> | ||
) => ({ | ||
...base, | ||
backgroundColor: isFocused ? "rgb(233 213 255 / 1)" : "white", | ||
}), | ||
} | ||
|
||
const handleSelect: ( | ||
newValue: MultiValue<any>, | ||
actionMeta: ActionMeta<any> | ||
) => void = (option) => { | ||
const breeds = option.map((o) => o.label) | ||
setSelectedBreeds(breeds) | ||
} | ||
|
||
const getBreeds = async () => { | ||
try { | ||
const res = await api.fetchBreeds() | ||
const options = res.map((r) => ({ value: r, label: r })) | ||
setSelectOptions(options) | ||
} catch (msg) { | ||
console.log(msg) | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
getBreeds() | ||
}, []) | ||
|
||
return ( | ||
<Select | ||
isMulti | ||
styles={customStyles} | ||
options={selectOptions} | ||
onChange={handleSelect} | ||
/> | ||
) | ||
} | ||
|
||
export default CustomSelect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { FC } from "react" | ||
|
||
interface InputComponentProps { | ||
label: string | ||
value: string | ||
type: React.HTMLInputTypeAttribute | ||
handleChange: (value: React.ChangeEvent<HTMLInputElement>) => void | ||
} | ||
|
||
const InputComponent: FC<InputComponentProps> = ({ | ||
label, | ||
value, | ||
type, | ||
handleChange, | ||
}) => { | ||
return ( | ||
<div className="flex flex-col gap-2 sm:gap-4"> | ||
<label htmlFor={label}> | ||
{label.charAt(0).toUpperCase() + label.slice(1).toLowerCase()} | ||
</label> | ||
<input | ||
required | ||
className="flex items-center p-2 bg-white rounded-md border-2 border-md" | ||
name={label} | ||
id={label} | ||
type={type} | ||
value={value} | ||
onChange={handleChange} | ||
placeholder={ | ||
label.charAt(0).toUpperCase() + label.slice(1).toLowerCase() | ||
} | ||
/> | ||
</div> | ||
) | ||
} | ||
|
||
export default InputComponent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { FC } from "react" | ||
import { Dog } from "../utils/requests/types" | ||
import Button from "./Button" | ||
|
||
interface MatchCardProps { | ||
match: Dog | ||
resetMatch: Function | ||
} | ||
|
||
const MatchCard: FC<MatchCardProps> = ({ match, resetMatch }) => { | ||
const handleClick = () => { | ||
resetMatch() | ||
} | ||
|
||
return ( | ||
<div className="bg-white rounded-3xl flex flex-col items-center gap-5 px-12 py-12 max-w-md md:px-20"> | ||
<img | ||
className=" w-2/5 rounded-full aspect-square object-cover" | ||
src={match.img} | ||
alt="Dog image" | ||
/> | ||
<div className="w-8 h-1 bg-title rounded-sm" /> | ||
<div className="flex flex-col gap-3 items-center"> | ||
<h1 className="font-title font-md text-title">Meet {match.name}</h1> | ||
<p className="text-center text-body text-xs"> | ||
{generateDogParagraph(match.name, match.age)} | ||
</p> | ||
</div> | ||
<Button | ||
text="Adopt me :)" | ||
type="button" | ||
variant="primary" | ||
onClick={handleClick} | ||
/> | ||
</div> | ||
) | ||
} | ||
|
||
export default MatchCard | ||
|
||
const generateDogParagraph = (name: string, age: number) => { | ||
// Array of possible sentences with placeholders for the name | ||
const sentences = [ | ||
"Hello, my name is [name], and I am a loving and friendly companion looking for my forever home. At [age] years old, I have the perfect balance of playfulness and maturity.", | ||
"Meet [name], the adorable dog ready to bring joy and loyalty into your life. With [age] years of experience, I've learned to be the most loyal and trustworthy companion you could ask for.", | ||
"Hello there! I'm [name], a [age]-year-old furry bundle of happiness eager to join your family. I have a heart full of love to give and an energetic spirit that will keep you entertained and active.", | ||
"Say hello to [name], a [age]-year-old dog with a heart of gold. I'm ready to shower you with unconditional love, cuddles, and loyalty. I'll be your steadfast companion through thick and thin.", | ||
"Greetings! My name is [name], and at [age] years old, I've mastered the art of being a perfect cuddle buddy. With my charming personality and gentle nature, I'll bring warmth and happiness to your home.", | ||
"Introducing [name], a [age]-year-old canine treasure seeking a loving family. I come with a winning smile, a wagging tail, and a heart full of affection. Let's embark on countless adventures together!", | ||
] | ||
|
||
// Choose a random sentence | ||
const randomIndex = Math.floor(Math.random() * sentences.length) | ||
let paragraph = sentences[randomIndex] | ||
|
||
// Replace the placeholder [name] with the provided name | ||
paragraph = paragraph.replace(/\[name\]/g, name) | ||
|
||
// Replace the placeholder [age] with the provided age | ||
paragraph = paragraph.replace(/\[age\]/g, age.toString()) | ||
|
||
return paragraph | ||
} |
Oops, something went wrong.
499e164
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
dog-matcher – ./
dog-matcher-git-main-kahan.vercel.app
dog-matcher.vercel.app
dog-matcher-kahan.vercel.app