Handle website delete. Added response helper functions.

This commit is contained in:
Mike Cao 2020-08-07 17:19:42 -07:00
parent 0a411a9ad6
commit c4b75e4aec
31 changed files with 314 additions and 96 deletions

View file

@ -8,13 +8,15 @@ import Trash from 'assets/trash.svg';
import Plus from 'assets/plus.svg';
import { get } from 'lib/web';
import Modal from './common/Modal';
import WebsiteForm from './forms/WebsiteForm';
import WebsiteEditForm from './forms/WebsiteEditForm';
import styles from './Settings.module.css';
import WebsiteDeleteForm from './forms/WebsiteDeleteForm';
export default function Settings() {
const [data, setData] = useState();
const [edit, setEdit] = useState();
const [del, setDelete] = useState();
const [add, setAdd] = useState();
const [saved, setSaved] = useState(0);
const columns = [
@ -44,6 +46,7 @@ export default function Settings() {
}
function handleClose() {
setAdd(null);
setEdit(null);
setDelete(null);
}
@ -64,14 +67,28 @@ export default function Settings() {
<Page>
<PageHeader>
<div>Websites</div>
<Button icon={<Plus />} size="S">
<Button icon={<Plus />} size="S" onClick={() => setAdd(true)}>
<div>Add website</div>
</Button>
</PageHeader>
<Table columns={columns} rows={data} />
{edit && (
<Modal title="Edit website">
<WebsiteForm initialValues={edit} onSave={handleSave} onClose={handleClose} />
<WebsiteEditForm initialValues={edit} onSave={handleSave} onClose={handleClose} />
</Modal>
)}
{add && (
<Modal title="Add website">
<WebsiteEditForm
initialValues={{ name: '', domain: '' }}
onSave={handleSave}
onClose={handleClose}
/>
</Modal>
)}
{del && (
<Modal title="Delete website">
<WebsiteDeleteForm initialValues={del} onSave={handleSave} onClose={handleClose} />
</Modal>
)}
</Page>

View file

@ -36,7 +36,7 @@ export default function DropDown({
<div ref={ref} className={classNames(styles.dropdown, className)} onClick={handleShowMenu}>
<div className={styles.value}>
{options.find(e => e.value === value)?.label}
<Icon icon={<Chevron />} size="S" className={styles.icon} />
<Icon icon={<Chevron />} size="S" />
</div>
{showMenu && <Menu className={menuClassName} options={options} onSelect={handleSelect} />}
</div>

View file

@ -5,18 +5,12 @@
}
.value {
display: flex;
justify-content: space-between;
white-space: nowrap;
position: relative;
padding: 4px 32px 4px 16px;
padding: 4px 16px;
border: 1px solid var(--gray500);
border-radius: 4px;
cursor: pointer;
}
.icon {
position: absolute;
top: 0;
bottom: 0;
right: 12px;
margin: auto;
}

View file

@ -31,7 +31,6 @@
border: 1px solid var(--gray300);
padding: 30px;
border-radius: 4px;
overflow: hidden;
}
.header {

View file

@ -56,7 +56,7 @@ export default function LoginForm() {
<FormError name="password" />
</FormRow>
<FormButtons>
<Button className={styles.button} type="submit">
<Button type="submit" variant="action">
Login
</Button>
</FormButtons>

View file

@ -0,0 +1,68 @@
import React, { useState } from 'react';
import { Formik, Form, Field } from 'formik';
import { del } from 'lib/web';
import Button from 'components/interface/Button';
import FormLayout, {
FormButtons,
FormError,
FormMessage,
FormRow,
} from 'components/layout/FormLayout';
const validate = ({ confirmation }) => {
const errors = {};
if (confirmation !== 'DELETE') {
errors.confirmation = !confirmation ? 'Required' : 'Invalid';
}
return errors;
};
export default function WebsiteDeleteForm({ initialValues, onSave, onClose }) {
const [message, setMessage] = useState();
const handleSubmit = async ({ website_id }) => {
const response = await del(`/api/website/${website_id}`);
if (response) {
onSave();
} else {
setMessage('Something went wrong.');
}
};
return (
<FormLayout>
<Formik
initialValues={{ confirmation: '', ...initialValues }}
validate={validate}
onSubmit={handleSubmit}
>
{() => (
<Form>
<div>
Are your sure you want to delete <b>{initialValues.name}</b>?
</div>
<div>All associated data will be deleted as well.</div>
<p>
Type <b>DELETE</b> in the box below to confirm.
</p>
<FormRow>
<label htmlFor="confirmation">Confirm</label>
<Field name="confirmation" />
<FormError name="confirmation" />
</FormRow>
<FormButtons>
<Button type="submit" variant="danger">
Delete
</Button>
<Button onClick={onClose}>Cancel</Button>
</FormButtons>
<FormMessage>{message}</FormMessage>
</Form>
)}
</Formik>
</FormLayout>
);
}

View file

@ -1,6 +1,5 @@
import React, { useState } from 'react';
import { Formik, Form, Field } from 'formik';
import Router from 'next/router';
import { post } from 'lib/web';
import Button from 'components/interface/Button';
import FormLayout, {
@ -23,7 +22,7 @@ const validate = ({ name, domain }) => {
return errors;
};
export default function WebsiteForm({ initialValues, onSave, onClose }) {
export default function WebsiteEditForm({ initialValues, onSave, onClose }) {
const [message, setMessage] = useState();
const handleSubmit = async values => {
@ -52,7 +51,9 @@ export default function WebsiteForm({ initialValues, onSave, onClose }) {
<FormError name="domain" />
</FormRow>
<FormButtons>
<Button type="submit">Save</Button>
<Button type="submit" variant="action">
Save
</Button>
<Button onClick={onClose}>Cancel</Button>
</FormButtons>
<FormMessage>{message}</FormMessage>

View file

@ -7,6 +7,7 @@ export default function Button({
type = 'button',
icon,
size,
variant,
children,
className,
onClick = () => {},
@ -17,6 +18,8 @@ export default function Button({
className={classNames(styles.button, className, {
[styles.small]: size === 'S',
[styles.large]: size === 'L',
[styles.action]: variant === 'action',
[styles.danger]: variant === 'danger',
})}
onClick={onClick}
>

View file

@ -26,3 +26,21 @@
.large {
font-size: var(--font-size-large);
}
.action {
color: var(--gray50) !important;
background: var(--gray900) !important;
}
.action:hover {
background: var(--gray800) !important;
}
.danger {
color: var(--gray50) !important;
background: var(--red500) !important;
}
.danger:hover {
background: var(--red400) !important;
}

View file

@ -1,4 +1,5 @@
import React from 'react';
import { useSpring, animated } from 'react-spring';
import classNames from 'classnames';
import { ErrorMessage } from 'formik';
import styles from './FormLayout.module.css';
@ -11,9 +12,19 @@ export const FormButtons = ({ className, children }) => (
<div className={classNames(styles.buttons, className)}>{children}</div>
);
export const FormError = ({ name }) => (
<ErrorMessage name={name}>{msg => <div className={styles.error}>{msg}</div>}</ErrorMessage>
);
export const FormError = ({ name }) => {
return <ErrorMessage name={name}>{msg => <ErrorTag msg={msg} />}</ErrorMessage>;
};
const ErrorTag = ({ msg }) => {
const props = useSpring({ opacity: 1, from: { opacity: 0 } });
return (
<animated.div className={styles.error} style={props}>
{msg}
</animated.div>
);
};
export const FormRow = ({ children }) => <div className={styles.row}>{children}</div>;

View file

@ -20,11 +20,12 @@
.buttons {
display: flex;
justify-content: center;
margin-top: 20px;
}
.error {
color: var(--gray50);
background: var(--color-error);
background: var(--red400);
font-size: var(--font-size-small);
position: absolute;
display: flex;
@ -47,7 +48,7 @@
margin: auto;
width: 10px;
height: 10px;
background: var(--color-error);
background: var(--red400);
transform: rotate(45deg);
}