mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-06 02:26:49 +00:00
minor refactorings
This commit is contained in:
parent
2ac94f24f1
commit
fecfc95982
45 changed files with 152 additions and 297 deletions
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import { PreLoader } from "./components/PreLoader";
|
||||
import "./index.css";
|
||||
import MainLayout from "./layouts/MainLayout";
|
||||
|
|
@ -6,7 +5,7 @@ import { AppRouter } from "./router";
|
|||
import { Router } from "./router/Router";
|
||||
import { useAuth0 } from "./utils/auth0-spa";
|
||||
|
||||
export const App: FC = () => {
|
||||
export const App = () => {
|
||||
const { loading } = useAuth0();
|
||||
|
||||
return loading ? (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { MealSummary } from "../types/meal";
|
||||
|
||||
|
|
@ -7,22 +6,22 @@ type Props = {
|
|||
className?: string;
|
||||
};
|
||||
|
||||
export const CardEntry: FC<Props> = ({ meal, className = "col s12 m6" }) => {
|
||||
const { idMeal, strMeal, strMealThumb } = meal;
|
||||
return (
|
||||
<Link to={`/${idMeal}`}>
|
||||
<li>
|
||||
<div className={className}>
|
||||
<div className="card hoverable">
|
||||
<div className="card-image">
|
||||
<img src={strMealThumb} alt={strMeal} />
|
||||
</div>
|
||||
<div className="card-content">
|
||||
<h4>{strMeal}</h4>
|
||||
</div>
|
||||
export const CardEntry = ({
|
||||
meal: { idMeal, strMeal, strMealThumb },
|
||||
className = "col s12 m6",
|
||||
}: Props) => (
|
||||
<Link to={`/${idMeal}`}>
|
||||
<li>
|
||||
<div className={className}>
|
||||
<div className="card hoverable">
|
||||
<div className="card-image">
|
||||
<img src={strMealThumb} alt={strMeal} />
|
||||
</div>
|
||||
<div className="card-content">
|
||||
<h4>{strMeal}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
</div>
|
||||
</li>
|
||||
</Link>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { FC } from "react";
|
||||
|
||||
export const CopyrightText: FC = () => (
|
||||
export const CopyrightText = () => (
|
||||
<span className="grey-text text-darken-1">
|
||||
© 2020 - <span className="logo">Chef's</span> - Made with{" "}
|
||||
© {new Date().getFullYear()} - <span className="logo">Chef's</span> - Made with{" "}
|
||||
<span role="img" aria-label="heart">
|
||||
❤️
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import { FC } from "react";
|
||||
import { links } from "../constants";
|
||||
import { CopyrightText } from "./CopyrightText";
|
||||
import { FooterLink } from "./FooterLink";
|
||||
import { GitHubLink } from "./GitHubLink";
|
||||
|
||||
export const Footer: FC = () => {
|
||||
export const Footer = () => {
|
||||
const footerLinks = [...links, "random"];
|
||||
return (
|
||||
<footer className="page-footer">
|
||||
|
|
|
|||
|
|
@ -1,20 +1,16 @@
|
|||
import { FC } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { upFirstChar } from "../utils/methods";
|
||||
import { upFirstChar } from "../utils/string";
|
||||
|
||||
type Props = {
|
||||
link: string;
|
||||
textColor?: string;
|
||||
};
|
||||
|
||||
export const FooterLink: FC<Props> = ({ link, textColor = "" }) => {
|
||||
export const FooterLink = ({ link, textColor = "" }: Props) => {
|
||||
const textColorClass = `${textColor}-text`;
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
className={`${textColorClass} waves-effect text-lighten-3`}
|
||||
to={`/${link}`}
|
||||
>
|
||||
<Link className={`${textColorClass} waves-effect text-lighten-3`} to={`/${link}`}>
|
||||
{upFirstChar(link)}
|
||||
</Link>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { FC } from "react";
|
||||
|
||||
export const GitHubLink: FC = () => (
|
||||
export const GitHubLink = () => (
|
||||
<a
|
||||
className="grey-text text-darken-1 right"
|
||||
href="https://github.com/rjNemo/meal_planner"
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
import { FC } from "react";
|
||||
import { useAuth0 } from "../utils/auth0-spa";
|
||||
|
||||
type Props = {
|
||||
color: string;
|
||||
};
|
||||
type Props = { color: string };
|
||||
|
||||
export const LogInButton: FC<Props> = ({ color }) => {
|
||||
export const LogInButton = ({ color }: Props) => {
|
||||
const { loginWithRedirect } = useAuth0();
|
||||
const handleClick = () => {
|
||||
loginWithRedirect({});
|
||||
};
|
||||
const handleClick = () => loginWithRedirect({});
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`waves-effect waves-light btn ${color}`}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<button className={`waves-effect waves-light btn ${color}`} onClick={handleClick}>
|
||||
Log in
|
||||
</button>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import { FC } from "react";
|
||||
import { useAuth0 } from "../utils/auth0-spa";
|
||||
|
||||
export const LogOutButton: FC = () => {
|
||||
export const LogOutButton = () => {
|
||||
const { logout } = useAuth0();
|
||||
const handleClick = () => {
|
||||
logout();
|
||||
};
|
||||
const handleClick = () => logout();
|
||||
|
||||
return (
|
||||
<button className="waves-effect waves-teal btn-flat" onClick={handleClick}>
|
||||
Log out
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
import { FC } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export const Logo: FC = () => {
|
||||
return (
|
||||
<Link to="/" className="brand-logo">
|
||||
<img
|
||||
src="/logo192.png"
|
||||
alt="chef's logo"
|
||||
height="30px"
|
||||
style={{ position: "relative", top: "5px" }}
|
||||
/>
|
||||
<span className="logo orange-text text-accent-4">Chef's</span>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
export const Logo = () => (
|
||||
<Link to="/" className="brand-logo">
|
||||
<img
|
||||
src="/logo192.png"
|
||||
alt="chef's logo"
|
||||
height="30px"
|
||||
style={{ position: "relative", top: "5px" }}
|
||||
/>
|
||||
<span className="logo orange-text text-accent-4">Chef's</span>
|
||||
</Link>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC } from "react";
|
||||
import { MouseEventHandler } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { buttonURL, links } from "../constants";
|
||||
import { useAuth0 } from "../utils/auth0-spa";
|
||||
|
|
@ -8,9 +8,9 @@ import { Logo } from "./Logo";
|
|||
import { LogOutButton } from "./LogOutButton";
|
||||
import { RandomButton } from "./RandomButton";
|
||||
|
||||
type Props = { openNavClick: React.MouseEventHandler };
|
||||
type Props = { openNavClick: MouseEventHandler };
|
||||
|
||||
export const Navbar: FC<Props> = ({ openNavClick }) => {
|
||||
export const Navbar = ({ openNavClick }: Props) => {
|
||||
const { isAuthenticated } = useAuth0();
|
||||
|
||||
return (
|
||||
|
|
@ -23,22 +23,12 @@ export const Navbar: FC<Props> = ({ openNavClick }) => {
|
|||
{links.map((link, i) => (
|
||||
<FooterLink key={i} link={link} textColor="black" />
|
||||
))}
|
||||
{isAuthenticated && (
|
||||
<FooterLink link="profile" textColor="black" />
|
||||
)}
|
||||
{isAuthenticated && <FooterLink link="profile" textColor="black" />}
|
||||
<li>
|
||||
<RandomButton
|
||||
url={buttonURL}
|
||||
size="small"
|
||||
color="orange darken-2"
|
||||
/>
|
||||
<RandomButton url={buttonURL} size="small" color="orange darken-2" />
|
||||
</li>
|
||||
<li>
|
||||
{!isAuthenticated ? (
|
||||
<LogInButton color="orange lighten-1" />
|
||||
) : (
|
||||
<LogOutButton />
|
||||
)}
|
||||
{!isAuthenticated ? <LogInButton color="orange lighten-1" /> : <LogOutButton />}
|
||||
</li>
|
||||
</ul>
|
||||
<Link
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { FC } from "react";
|
||||
|
||||
export const PreLoader: FC = () => (
|
||||
export const PreLoader = () => (
|
||||
<div className="preloader-wrapper active">
|
||||
<div className="spinner-layer spinner-red-only">
|
||||
<div className="circle-clipper left">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useMeal } from "../store/meal";
|
||||
import { fetchRandomMeal } from "../store/meal/async";
|
||||
|
|
@ -9,7 +8,7 @@ type Props = {
|
|||
color?: string;
|
||||
};
|
||||
|
||||
export const RandomButton: FC<Props> = ({ url, size = "large", color }) => {
|
||||
export const RandomButton = ({ url, size = "large", color }: Props) => {
|
||||
const classString = `waves-effect waves-light btn-${size} ${color}`;
|
||||
const { dispatch } = useMeal();
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
import React, { ChangeEvent, FC, useState } from "react";
|
||||
import { ChangeEvent, MouseEventHandler, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { useMeal } from "../store/meal";
|
||||
import { fetchSearchResults } from "../store/meal/async";
|
||||
|
||||
export const SearchBar: FC = () => {
|
||||
export const SearchBar = () => {
|
||||
const { dispatch } = useMeal();
|
||||
const [searchString, setSearchString] = useState("");
|
||||
const getSearchResults: React.MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
searchString === ""
|
||||
? e.preventDefault()
|
||||
: fetchSearchResults(dispatch, searchString);
|
||||
const getSearchResults: MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||
searchString === "" ? e.preventDefault() : fetchSearchResults(dispatch, searchString);
|
||||
};
|
||||
|
||||
const clearSearchBar = () => {
|
||||
|
|
@ -17,10 +15,8 @@ export const SearchBar: FC = () => {
|
|||
dispatch({ type: "clearSearchResults" });
|
||||
};
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = e.target;
|
||||
const handleChange = ({ target: { value } }: ChangeEvent<HTMLInputElement>) =>
|
||||
setSearchString(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="section">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC } from "react";
|
||||
import { MouseEventHandler } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { buttonURL, links } from "../constants";
|
||||
import ChefImage from "../images/chef.svg";
|
||||
|
|
@ -9,9 +9,12 @@ import { LogInButton } from "./LogInButton";
|
|||
import { LogOutButton } from "./LogOutButton";
|
||||
import { RandomButton } from "./RandomButton";
|
||||
|
||||
type Props = { showNav: boolean; closeNavClick: React.MouseEventHandler };
|
||||
type Props = {
|
||||
showNav: boolean;
|
||||
closeNavClick: MouseEventHandler;
|
||||
};
|
||||
|
||||
export const SideNav: FC<Props> = ({ showNav, closeNavClick }) => {
|
||||
export const SideNav = ({ showNav, closeNavClick }: Props) => {
|
||||
const { isAuthenticated, user } = useAuth0();
|
||||
let transformStyle = {
|
||||
transform: showNav ? "translateX(0%)" : "translateX(-105%)",
|
||||
|
|
@ -32,8 +35,7 @@ export const SideNav: FC<Props> = ({ showNav, closeNavClick }) => {
|
|||
left: "0",
|
||||
right: "0",
|
||||
bottom: "0",
|
||||
backgroundColor:
|
||||
"rgba(0,0,0,0.5)" /* Black background with opacity */,
|
||||
backgroundColor: "rgba(0,0,0,0.5)" /* Black background with opacity */,
|
||||
zIndex: 2 /* Specify a stack order in case you're using a different order for other elements */,
|
||||
// cursor: "pointer" /* Add a pointer on hover */
|
||||
}}
|
||||
|
|
@ -65,11 +67,7 @@ export const SideNav: FC<Props> = ({ showNav, closeNavClick }) => {
|
|||
</li>
|
||||
<li>
|
||||
<Link to="#">
|
||||
{!isAuthenticated ? (
|
||||
<LogInButton color="orange lighten-1" />
|
||||
) : (
|
||||
<LogOutButton />
|
||||
)}
|
||||
{!isAuthenticated ? <LogInButton color="orange lighten-1" /> : <LogOutButton />}
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import { Link, useRouteMatch } from "react-router-dom";
|
||||
|
||||
type Props = {
|
||||
|
|
@ -6,7 +5,7 @@ type Props = {
|
|||
strCategoryThumb: string;
|
||||
};
|
||||
|
||||
const CategoriesEntry: FC<Props> = ({ strCategory, strCategoryThumb }) => {
|
||||
const CategoriesEntry = ({ strCategory, strCategoryThumb }: Props) => {
|
||||
const { url } = useRouteMatch();
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import PageLayout from "../../../layouts/PageLayout";
|
||||
import CategoriesEntry from "./CategoriesEntry";
|
||||
|
||||
|
|
@ -6,15 +5,11 @@ type Props = {
|
|||
categories: { strCategory: string; strCategoryThumb: string }[];
|
||||
};
|
||||
|
||||
export const CategoriesPage: FC<Props> = ({ categories }) => (
|
||||
export const CategoriesPage = ({ categories }: Props) => (
|
||||
<PageLayout title="Chef's Categories">
|
||||
<ul>
|
||||
{categories.map(({ strCategory, strCategoryThumb }, i) => (
|
||||
<CategoriesEntry
|
||||
key={i}
|
||||
strCategory={strCategory}
|
||||
strCategoryThumb={strCategoryThumb}
|
||||
/>
|
||||
<CategoriesEntry key={i} strCategory={strCategory} strCategoryThumb={strCategoryThumb} />
|
||||
))}
|
||||
</ul>
|
||||
</PageLayout>
|
||||
|
|
|
|||
|
|
@ -6,9 +6,7 @@ import { CategoriesPage } from "./components/CategoriesPage";
|
|||
export const Categories = () => {
|
||||
const [categories, setCategories] = useState({ categories: [] });
|
||||
|
||||
const getCategories = () => {
|
||||
getData("categories").then((data) => setCategories(data));
|
||||
};
|
||||
const getCategories = () => getData("categories").then((data) => setCategories(data));
|
||||
|
||||
useEffect(() => {
|
||||
getCategories();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import { CardEntry } from "../../../components/CardEntry";
|
||||
import PageLayout from "../../../layouts/PageLayout";
|
||||
import { MealSummary } from "../../../types/meal";
|
||||
|
|
@ -8,7 +7,7 @@ type Props = {
|
|||
strCategory: string;
|
||||
};
|
||||
|
||||
export const CategoryPage: FC<Props> = ({ meals, strCategory }) => (
|
||||
export const CategoryPage = ({ meals, strCategory }: Props) => (
|
||||
<PageLayout title={`Chef's ${strCategory} Recipes`}>
|
||||
<ul>
|
||||
<div className="row">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { FC, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Redirect, useParams } from "react-router-dom";
|
||||
import { getData } from "../../services/api";
|
||||
import { CategoryPage } from "./components/CategoryPage";
|
||||
|
||||
export const Category: FC = () => {
|
||||
export const Category = () => {
|
||||
const { strCategory } = useParams<{ strCategory: string }>();
|
||||
const [meals, setMeals] = useState({ meals: [] });
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC, useState } from "react";
|
||||
import { useState, FormEvent } from "react";
|
||||
import { ContactFormInput } from "./ContactFormInput";
|
||||
import { ContactFormSubmitButton } from "./ContactFormSubmitButton";
|
||||
import { ContactFormTextArea } from "./ContactFormTextArea";
|
||||
|
|
@ -7,14 +7,14 @@ type Props = {
|
|||
setIsSubmitted: (value: boolean) => void;
|
||||
};
|
||||
|
||||
export const ContactForm: FC<Props> = ({ setIsSubmitted }) => {
|
||||
export const ContactForm = ({ setIsSubmitted }: Props) => {
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [phone, setPhone] = useState("");
|
||||
const [message, setMessage] = useState("");
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitted(true);
|
||||
};
|
||||
|
|
@ -24,45 +24,20 @@ export const ContactForm: FC<Props> = ({ setIsSubmitted }) => {
|
|||
<div className="row">
|
||||
<div className="col s12">
|
||||
<div className="col s12 m6">
|
||||
<ContactFormInput
|
||||
id="First Name"
|
||||
value={firstName}
|
||||
dispatch={setFirstName}
|
||||
/>
|
||||
<ContactFormInput id="First Name" value={firstName} dispatch={setFirstName} />
|
||||
</div>
|
||||
<div className="col s12 m6">
|
||||
<ContactFormInput
|
||||
id="Last Name"
|
||||
value={lastName}
|
||||
dispatch={setLastName}
|
||||
/>
|
||||
<ContactFormInput id="Last Name" value={lastName} dispatch={setLastName} />
|
||||
</div>
|
||||
<div className="col s12 m6">
|
||||
<ContactFormInput
|
||||
id="Email"
|
||||
type="email"
|
||||
value={email}
|
||||
dispatch={setEmail}
|
||||
/>
|
||||
<ContactFormInput id="Email" type="email" value={email} dispatch={setEmail} />
|
||||
</div>
|
||||
<div className="col s12 m6">
|
||||
<ContactFormInput
|
||||
id="Phone"
|
||||
value={phone}
|
||||
type="tel"
|
||||
dispatch={setPhone}
|
||||
/>
|
||||
<ContactFormInput id="Phone" value={phone} type="tel" dispatch={setPhone} />
|
||||
</div>
|
||||
<div className="col s12">
|
||||
<ContactFormTextArea
|
||||
id="Message"
|
||||
value={message}
|
||||
dispatch={setMessage}
|
||||
/>
|
||||
<ContactFormSubmitButton
|
||||
text="Send Message"
|
||||
color="orange darken-2"
|
||||
/>
|
||||
<ContactFormTextArea id="Message" value={message} dispatch={setMessage} />
|
||||
<ContactFormSubmitButton text="Send Message" color="orange darken-2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,14 @@
|
|||
import React, { FC } from "react";
|
||||
import { ChangeEventHandler, Dispatch, SetStateAction } from "react";
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
type?: string;
|
||||
value: string;
|
||||
dispatch: React.Dispatch<React.SetStateAction<string>>;
|
||||
dispatch: Dispatch<SetStateAction<string>>;
|
||||
};
|
||||
|
||||
export const ContactFormInput: FC<Props> = ({
|
||||
id,
|
||||
type = "text",
|
||||
value,
|
||||
dispatch,
|
||||
}) => {
|
||||
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
export const ContactFormInput = ({ id, type = "text", value, dispatch }: Props) => {
|
||||
const handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
e.preventDefault();
|
||||
dispatch(e.target.value);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,16 +1,10 @@
|
|||
import { FC } from "react";
|
||||
|
||||
type Props = {
|
||||
text: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
export const ContactFormSubmitButton: FC<Props> = ({ text, color }) => (
|
||||
<button
|
||||
className={`waves-effect waves-light btn ${color}`}
|
||||
type="submit"
|
||||
name="submit"
|
||||
>
|
||||
export const ContactFormSubmitButton = ({ text, color }: Props) => (
|
||||
<button className={`waves-effect waves-light btn ${color}`} type="submit" name="submit">
|
||||
<i className="material-icons right">send</i> {text}
|
||||
</button>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
export function ContactFormSubmitted() {
|
||||
return (
|
||||
<div className="container center-align">
|
||||
<img
|
||||
className="responsive-img"
|
||||
src={require("../../../images/mail_sent.svg")}
|
||||
alt="mail_sent"
|
||||
width="30%"
|
||||
/>
|
||||
<h4>Thank you for your message</h4>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export const ContactFormSubmitted = () => (
|
||||
<div className="container center-align">
|
||||
<img
|
||||
className="responsive-img"
|
||||
src={require("../../../images/mail_sent.svg")}
|
||||
alt="mail_sent"
|
||||
width="30%"
|
||||
/>
|
||||
<h4>Thank you for your message</h4>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import React, { FC } from "react";
|
||||
import { ChangeEventHandler, Dispatch, FC, SetStateAction } from "react";
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
value: string;
|
||||
dispatch: React.Dispatch<React.SetStateAction<string>>;
|
||||
dispatch: Dispatch<SetStateAction<string>>;
|
||||
};
|
||||
|
||||
export const ContactFormTextArea: FC<Props> = ({ id, value, dispatch }) => {
|
||||
const handleChange: React.ChangeEventHandler<HTMLTextAreaElement> = (e) => {
|
||||
const handleChange: ChangeEventHandler<HTMLTextAreaElement> = (e) => {
|
||||
e.preventDefault();
|
||||
dispatch(e.target.value);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { FC, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import PageLayout from "../../layouts/PageLayout";
|
||||
import { ContactForm } from "./components/ContactForm";
|
||||
import { ContactFormSubmitted } from "./components/ContactFormSubmitted";
|
||||
|
||||
export const Contact: FC = () => {
|
||||
export const Contact = () => {
|
||||
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||
|
||||
return isSubmitted ? (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { FC } from "react";
|
||||
import { RandomButton } from "../../components/RandomButton";
|
||||
import { buttonURL } from "../../constants";
|
||||
import HeroImage from "../../images/chef.svg";
|
||||
|
||||
export const Home: FC = () => (
|
||||
export const Home = () => (
|
||||
<section className="container ">
|
||||
<div className="row">
|
||||
<div className="col s12 m6">
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
import { FC } from "react";
|
||||
type Props = { ingredients: string[][] };
|
||||
|
||||
type Props = {
|
||||
ingredients: string[][];
|
||||
};
|
||||
|
||||
export const MealIngredientList: FC<Props> = ({ ingredients }) => (
|
||||
export const MealIngredientList = ({ ingredients }: Props) => (
|
||||
<div className="ingredientList">
|
||||
<table className="striped highlight responsive-table">
|
||||
<thead>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { FC } from "react";
|
||||
import Meal from "../../../types/meal";
|
||||
import { Meal } from "../../../types/meal";
|
||||
import { MealIngredientList } from "./MealIngredientList";
|
||||
import { MealPresentation } from "./MealPresentation";
|
||||
import { MealRecipe } from "./MealRecipe";
|
||||
|
|
@ -11,12 +10,7 @@ type Props = {
|
|||
handleFavChange: () => void;
|
||||
};
|
||||
|
||||
export const MealPage: FC<Props> = ({
|
||||
meal,
|
||||
ingredients,
|
||||
recipe,
|
||||
handleFavChange,
|
||||
}) => (
|
||||
export const MealPage = ({ meal, ingredients, recipe, handleFavChange }: Props) => (
|
||||
<section className="container">
|
||||
<div className="row">
|
||||
<div className="col s12 l6">
|
||||
|
|
|
|||
|
|
@ -1,22 +1,15 @@
|
|||
import { FC } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import Meal from "../../../types/meal";
|
||||
import { Meal } from "../../../types/meal";
|
||||
|
||||
type Props = {
|
||||
meal: Meal;
|
||||
handleFavChange: () => void;
|
||||
};
|
||||
|
||||
export const MealPresentation: FC<Props> = ({ meal, handleFavChange }) => {
|
||||
const {
|
||||
mealName,
|
||||
imgAddress,
|
||||
videoAddress,
|
||||
mealCategory,
|
||||
mealArea,
|
||||
isFav,
|
||||
} = meal;
|
||||
|
||||
export const MealPresentation = ({
|
||||
meal: { mealName, imgAddress, videoAddress, mealCategory, mealArea, isFav },
|
||||
handleFavChange,
|
||||
}: Props) => {
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="col s12">
|
||||
|
|
@ -45,16 +38,11 @@ export const MealPresentation: FC<Props> = ({ meal, handleFavChange }) => {
|
|||
</div>
|
||||
|
||||
<div className="chip">
|
||||
<b>
|
||||
{isFav ? "Remove from favourites" : "Add to favourites"}:
|
||||
</b>
|
||||
<b>{isFav ? "Remove from favourites" : "Add to favourites"}:</b>
|
||||
|
||||
<Link to="#">
|
||||
{" "}
|
||||
<i
|
||||
className="material-icons tiny"
|
||||
onClick={handleFavChange}
|
||||
>
|
||||
<i className="material-icons tiny" onClick={handleFavChange}>
|
||||
{isFav ? "favorite" : "favorite_border"}
|
||||
</i>
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
import { FC } from "react";
|
||||
type Props = { recipe: string };
|
||||
|
||||
type Props = {
|
||||
recipe: string;
|
||||
};
|
||||
|
||||
export const MealRecipe: FC<Props> = ({ recipe }) => (
|
||||
export const MealRecipe = ({ recipe }: Props) => (
|
||||
<div className="recipe">
|
||||
<div className="divider" />
|
||||
<h3>Instructions</h3>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { FC, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useFirebase } from "../../services/Firebase";
|
||||
import { useMeal } from "../../store/meal";
|
||||
|
|
@ -8,7 +8,7 @@ import { NotFound } from "../NotFound";
|
|||
import { MealPage } from "./components/MealPage";
|
||||
import { buildIngredientList, buildMealProps } from "./service";
|
||||
|
||||
export const Meal: FC = () => {
|
||||
export const Meal = () => {
|
||||
// hooks
|
||||
const { user, isAuthenticated } = useAuth0();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { FC } from "react";
|
||||
import { RandomButton } from "../../components/RandomButton";
|
||||
|
||||
export const NotFound: FC = () => (
|
||||
export const NotFound = () => (
|
||||
<div className="container center-align">
|
||||
<div className="row">
|
||||
<h1>Wrong Way!</h1>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import { CardEntry } from "../../../components/CardEntry";
|
||||
import { MealSummary } from "../../../types/meal";
|
||||
|
||||
|
|
@ -7,15 +6,10 @@ type Props = {
|
|||
meals: MealSummary[];
|
||||
};
|
||||
|
||||
export const ProfilePage: FC<Props> = ({ user, meals }) => (
|
||||
export const ProfilePage = ({ user, meals }: Props) => (
|
||||
<div className="container">
|
||||
<div className="row valign-wrapper">
|
||||
<img
|
||||
className="left circle responsive-img"
|
||||
src={user.picture}
|
||||
alt="Avatar"
|
||||
width="15%"
|
||||
/>
|
||||
<img className="left circle responsive-img" src={user.picture} alt="Avatar" width="15%" />
|
||||
<h2 className="col s9">{user.name}</h2>
|
||||
</div>
|
||||
<div className="row">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { FC, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { PreLoader } from "../../components/PreLoader";
|
||||
import { useFirebase } from "../../services/Firebase";
|
||||
import { MealSummary } from "../../types/meal";
|
||||
import { useAuth0 } from "../../utils/auth0-spa";
|
||||
import { ProfilePage } from "./components/ProfilePage";
|
||||
|
||||
export const Profile: FC = () => {
|
||||
export const Profile = () => {
|
||||
const { loading, user } = useAuth0();
|
||||
const [favs, setFavs] = useState([] as MealSummary[]);
|
||||
const db = useFirebase();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import BreakfastImage from "../../../images/breakfast.svg";
|
||||
import PageLayout from "../../../layouts/PageLayout";
|
||||
import { MealSummary } from "../../../types/meal";
|
||||
|
|
@ -9,13 +8,11 @@ type Props = {
|
|||
searchResults: MealSummary[];
|
||||
};
|
||||
|
||||
export const SearchPage: FC<Props> = ({ searchString, searchResults }) => (
|
||||
export const SearchPage = ({ searchString, searchResults }: Props) => (
|
||||
<PageLayout title={`Results for: ${searchString}`}>
|
||||
{!searchResults ? (
|
||||
<div className="center-align">
|
||||
<p>
|
||||
No results to display, instead there is a picture of my breakfast.
|
||||
</p>
|
||||
<p>No results to display, instead there is a picture of my breakfast.</p>
|
||||
<img src={BreakfastImage} alt="Nothing here!" width="70%" />
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { FC } from "react";
|
||||
import { CardEntry } from "../../../components/CardEntry";
|
||||
import { MealSummary } from "../../../types/meal";
|
||||
|
||||
type Props = {
|
||||
meal: MealSummary;
|
||||
};
|
||||
type Props = { meal: MealSummary };
|
||||
|
||||
export const SearchResult: FC<Props> = ({ meal }) => <CardEntry meal={meal} />;
|
||||
export const SearchResult = ({ meal }: Props) => <CardEntry meal={meal} />;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import { FC } from "react";
|
||||
import { useMeal } from "../../store/meal";
|
||||
import { SearchPage } from "./components/SearchPage";
|
||||
|
||||
export const Search: FC = () => {
|
||||
const { state } = useMeal();
|
||||
return (
|
||||
<SearchPage
|
||||
searchString={state.searchString}
|
||||
searchResults={state.search}
|
||||
/>
|
||||
);
|
||||
export const Search = () => {
|
||||
const {
|
||||
state: { searchString, search },
|
||||
} = useMeal();
|
||||
return <SearchPage searchString={searchString} searchResults={search} />;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FC, useState } from "react";
|
||||
import { FC, MouseEvent, MouseEventHandler, useState } from "react";
|
||||
import { Footer } from "../components/Footer";
|
||||
import { Navbar } from "../components/Navbar";
|
||||
import { SearchBar } from "../components/SearchBar";
|
||||
|
|
@ -7,20 +7,20 @@ import { SideNav } from "../components/SideNav";
|
|||
const MainLayout: FC = ({ children }) => {
|
||||
const [showNav, setShowNav] = useState(false);
|
||||
|
||||
const openNavClick: React.MouseEventHandler = (e) => {
|
||||
const openNavClick: MouseEventHandler = (e) => {
|
||||
e.preventDefault();
|
||||
setShowNav(true);
|
||||
document.addEventListener("keydown", handleEscKey);
|
||||
};
|
||||
|
||||
const closeNavClick = (e: React.MouseEvent) => {
|
||||
const closeNavClick = (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
setShowNav(false);
|
||||
document.removeEventListener("keydown", handleEscKey);
|
||||
};
|
||||
|
||||
const handleEscKey = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
const handleEscKey = ({ key }: KeyboardEvent) => {
|
||||
if (key === "Escape") {
|
||||
setShowNav(false);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { FC } from "react";
|
||||
import { Redirect, Route, Switch } from "react-router-dom";
|
||||
import { buttonURL } from "../constants";
|
||||
import { Categories } from "../containers/Categories";
|
||||
|
|
@ -11,7 +10,7 @@ import { Profile } from "../containers/Profile";
|
|||
import { Search } from "../containers/Search";
|
||||
import { PrivateRoute } from "./PrivateRoute";
|
||||
|
||||
const AppRouter: FC = () => (
|
||||
export const AppRouter = () => (
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Home />
|
||||
|
|
@ -52,5 +51,3 @@ const AppRouter: FC = () => (
|
|||
</Route>
|
||||
</Switch>
|
||||
);
|
||||
|
||||
export default AppRouter;
|
||||
|
|
|
|||
|
|
@ -2,15 +2,9 @@ import { FC, useEffect } from "react";
|
|||
import { Route, RouteProps } from "react-router-dom";
|
||||
import { useAuth0 } from "../utils/auth0-spa";
|
||||
|
||||
type Props = {
|
||||
component: FC;
|
||||
} & RouteProps;
|
||||
type Props = { component: FC } & RouteProps;
|
||||
|
||||
export const PrivateRoute: FC<Props> = ({
|
||||
component: Component,
|
||||
path,
|
||||
...rest
|
||||
}) => {
|
||||
export const PrivateRoute = ({ component: Component, path, ...rest }: Props) => {
|
||||
const { loading, isAuthenticated, loginWithRedirect } = useAuth0();
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -25,8 +19,7 @@ export const PrivateRoute: FC<Props> = ({
|
|||
fn();
|
||||
}, [loading, isAuthenticated, loginWithRedirect, path]);
|
||||
|
||||
const render = (props: any) =>
|
||||
isAuthenticated ? <Component {...props} /> : null;
|
||||
const render = (props: any) => (isAuthenticated ? <Component {...props} /> : null);
|
||||
|
||||
return <Route path={path} render={render} {...rest} />;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
import AppRouter from "./AppRouter";
|
||||
export { AppRouter };
|
||||
export { AppRouter } from "./AppRouter";
|
||||
|
|
|
|||
|
|
@ -23,10 +23,13 @@ const createURI = (keyword: string, option?: Option) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getData = (keyword: string, option?: Option) => {
|
||||
export const getData = async (keyword: string, option?: Option) => {
|
||||
const URI = createURI(keyword, option);
|
||||
|
||||
return fetch(URI)
|
||||
.then((response) => response.json())
|
||||
.catch((error) => console.warn(error + "url:" + URI));
|
||||
try {
|
||||
const response = await fetch(URI);
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
return console.warn(error + "url:" + URI);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1 @@
|
|||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export default interface Meal {
|
||||
export interface Meal {
|
||||
mealName: string;
|
||||
imgAddress: string;
|
||||
videoAddress: string;
|
||||
|
|
|
|||
Loading…
Reference in a new issue