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

Dev #1

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
3 changes: 2 additions & 1 deletion public/_redirects
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/* /index.html 200
/api/* https://myreacttemplate.herokuapp.com/api/v1/:splat 200
/* /index.html 200
50 changes: 34 additions & 16 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,45 @@ import DarkBlue from './Blue/DarkBlue.jsx';
import Layout from './Page/Layout.jsx';
import Form from './Forms/FormLayout.jsx';
import Search from './Search/Search.jsx';
import Auth from './Auth/Auth.jsx';
import AuthForm from './Auth/AuthForm.jsx';
import ProtectedRoute from './Auth/ProtectedRoute.jsx';
import UserProvider from '../state/UserContext.jsx';
import ListProvider from '../state/ListContext.jsx';
import { TodoLists } from './List/ShoppingList.jsx';
import { Lists } from './List/Lists.jsx';

export default function App() {
return (
<Router>
<Routes>
<Route element={<Layout />} >
<Route index element={<Colors />} />
<Route path="orange" element={<Orange />} />
<Route path="blue" element={<Blue />} >
<Route path="baby blue" index element={<BabyBlue />} />
<Route path="dark blue" element={<DarkBlue />} />
<Route path="blue green" element={<BlueGreen />} />
<UserProvider>
<Routes>
<Route element={<Layout />} >
<Route index element={<Colors />} />
<Route path="orange" element={<Orange />} />
<Route path="blue" element={<Blue />} >
<Route path="baby blue" index element={<BabyBlue />} />
<Route path="dark blue" element={<DarkBlue />} />
<Route path="blue green" element={<BlueGreen />} />
</Route>
<Route path="form" element={<Form />} />
<Route path="search" element={<Search />} />
<Route path="auth" element={<Auth />} >
<Route index element={<AuthForm mode="signin" />} />
<Route path="signup" element={<AuthForm mode="signup" />} />
</Route>
<Route element={<ProtectedRoute />} >
<Route element={<ListProvider />} >
<Route path="lists">
<Route index element={<Lists />} />
<Route path=":id" element={<TodoLists />} />
</Route>
</Route>
</Route>
</Route>
<Route path="form" element={<Form />} />
<Route path="search" element={<Search />} />

</Route>


<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</UserProvider>
</Router>
);
}
14 changes: 14 additions & 0 deletions src/components/Auth/Auth.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.Auth {
padding-top: 60px;
width: 400px;
margin: 0 auto;
display: grid;
gap: 30px;
border: 2px solid green;

}
h1 {
font-size: 1.2em;
font-weight: 600;
border: 2px solid red;
}
16 changes: 16 additions & 0 deletions src/components/Auth/Auth.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Navigate, Outlet } from 'react-router-dom';
import { useUser } from '../../state/UserContext.jsx';
import styles from './Auth.css';

export default function Auth() {
const user = useUser();

if(user) return <Navigate to="/"/>;

return (
<main className={styles.Auth}>
<h1>SHOP LIST</h1>
<Outlet/>
</main>
);
}
8 changes: 8 additions & 0 deletions src/components/Auth/AuthForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.AuthForm {
width: 400px;
background: teal;
padding: 25px;

display: grid;
gap: 30px;
}
77 changes: 77 additions & 0 deletions src/components/Auth/AuthForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* eslint-disable react/prop-types */
import { Link } from 'react-router-dom';
import { useAuth } from '../../state/UserContext.jsx';
import { InputControl, FormButton } from '../Forms/FormControl.jsx';
import { useForm } from '../Forms/useForm.js';
import styles from './AuthForm.css';

export default function AuthForm({ mode = 'signin' }) {
const { signUp, signIn, error } = useAuth();
const [credentials, handleChange] = useForm({
email: '',
password: '',
});
const handleSubmit = async (e) => {
e.preventDefault();
await type.action(credentials);
};

const signin = {
prompt: 'Please Sign In To Your Account',
button: 'Sign In',
switch: {
prompt: 'Dont Have An Account?',
link: 'signup',
}, action: signIn,
};

const signup = {
prompt: 'Create Your Account',
button: 'Sign Up',
switch: {
prompt: 'Already Have An Account?',
link: '../',
}, action: signUp,
};

const modes = { signin, signup };
const type = modes[mode];

return(
<form className={styles.AuthForm} onSubmit={handleSubmit}>
<h2>{type.prompt}</h2>
<InputControl
label="Email"
name="email"
type="email"
required value ={credentials.email}
onChange={handleChange}
/>
<InputControl
label="Password"
name="password"
type="password"
required value ={credentials.password}
onChange={handleChange}
/>
<FormButton>{type.prompt}</FormButton>
<p className="error">{error}</p>
<nav>
<Link to={type.switch.link}>{type.switch.prompt}</Link>
</nav>
</form>
);













}
9 changes: 9 additions & 0 deletions src/components/Auth/ProtectedRoute.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Navigate, Outlet } from 'react-router-dom';
import { useUser } from '../../state/UserContext.jsx';

export default function ProtectedRoute() {
const user = useUser();
if (!user) return <Navigate to="auth" />;

return <Outlet />;
}
4 changes: 4 additions & 0 deletions src/components/Forms/AddForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.AddForm {
display: flex;
align-items: flex-end;
}
31 changes: 31 additions & 0 deletions src/components/Forms/AddForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable react/prop-types */
import { useState } from 'react';
import { FormButton, InputControl } from './FormControl.jsx';
import styles from './FormLayout.css';

export default function AddForm({ onAdd, ...rest }) {
const [value, setValue] = useState('');

const handleChange = ({ target }) => setValue(target.value);
const handleSubmit = async (e) => {
e.preventDefault();
await onAdd(value);
setValue('');
};

return (
<div className={styles.page}>
<div className={styles.Forms}>
<form className={styles.Forms} onSubmit={handleSubmit}>
<InputControl
required value={value}
onChange={handleChange}
{...rest}
/>

<FormButton>Add Todo</FormButton>
</form>
</div>
</div>
);
}
20 changes: 20 additions & 0 deletions src/components/Forms/useForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useState } from 'react';

function getValue(target) {
return target.type === 'checkbox' ? target.checked : target.value;
}

export function useForm(initialData) {
const [data, setData] = useState({ ...initialData });

const handleChange = ({ target }) => {
setData((data) => ({
...data,
[target.name]: getValue(target),
}));
};

const reset = () => setData({ ...initialData });

return [data, handleChange, reset];
}
4 changes: 4 additions & 0 deletions src/components/List/ItemForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.ItemForm {
display: flex;
align-items: flex-end;
}
64 changes: 64 additions & 0 deletions src/components/List/ItemForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* eslint-disable react/prop-types */
import { useForm } from '../Forms/useForm.js';
import { FormButton, InputControl } from '../Forms/FormControl';
import styles from './ItemForm.css';

const initalData = {
todo: '',
location: '',
description: '',
qty: ''
};

export default function ItemForm({ onAdd, ...rest }) {
const [data, handleChange, reset] = useForm(initalData);

const handleSubmit = async (e) => {
e.preventDefault();
const { qty, ...obj } = data;
if (qty) obj.qty = qty;
await onAdd(obj);
reset();
};

return (
<form className={styles.ItemForm} onSubmit={handleSubmit}>
<InputControl
label="todo"
name="todo"
required
value={data.todo}
onChange={handleChange}
/>

<InputControl
label="location"
name="location"
required
value={data.location}
onChange={handleChange}
/>

<InputControl
label="description"
name="description"
required
value={data.description}
onChange={handleChange}
/>
<InputControl
label="Quantity"
name="qty"
type="number"
step="1"
value={data.qty}
onChange={handleChange}
{...rest}
/>

<FormButton>Add todo</FormButton>
</form>
);


}
18 changes: 18 additions & 0 deletions src/components/List/ListItem.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.ListItem {
display: grid;
grid-template-columns: 50px 1fr auto;
grid-auto-rows: 40px;
align-items: center;
gap: 10px;


}
.ListItem .RemoveButton {
padding: 5px;
border: 1px dashed red
}

.ListItem .Complete {
display: grid;
place-self: center;
}
25 changes: 25 additions & 0 deletions src/components/List/ListItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* eslint-disable react/prop-types */
import { FormButton } from '../Forms/FormControl.jsx';
import styles from './ListItem.css';

export default function ListItem({ item, onComplete, onRemove }) {
const { complete, qty, location, todo, description } = item;

return (
<li className={styles.ListItem}>
{complete ? (
<span className={styles.Complete}>✔</span>
) : (
<FormButton onClick={() => onComplete(item)} icon>✅</FormButton>
)}

<span>
{qty} {todo} {location} {description}
</span>

<button className={styles.RemoveButton} onClick={() => onRemove(item)}>
🗑️
</button>
</li>
);
}
Loading