mirror of
https://github.com/pawelmalak/flame.git
synced 2025-07-23 13:29:35 +02:00
Table component. Bookmarks edit view
This commit is contained in:
parent
4eaf9659d1
commit
bd5354a2e3
12 changed files with 281 additions and 137 deletions
|
@ -1,58 +1,8 @@
|
||||||
.TableContainer {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
width: 100%;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.Table th,
|
|
||||||
.Table td {
|
|
||||||
/* border: 1px solid orange; */
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Head */
|
|
||||||
|
|
||||||
.Table th {
|
|
||||||
--header-radius: 4px;
|
|
||||||
background-color: var(--color-primary);
|
|
||||||
color: var(--color-background);
|
|
||||||
}
|
|
||||||
|
|
||||||
.Table th:first-child {
|
|
||||||
border-top-left-radius: var(--header-radius);
|
|
||||||
border-bottom-left-radius: var(--header-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.Table th:last-child {
|
|
||||||
border-top-right-radius: var(--header-radius);
|
|
||||||
border-bottom-right-radius: var(--header-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Body */
|
|
||||||
|
|
||||||
.Table td {
|
|
||||||
/* opacity: 0.5; */
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .Table td:hover {
|
|
||||||
opacity: 1;
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* Actions */
|
|
||||||
|
|
||||||
.TableActions {
|
.TableActions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.TableAction {
|
.TableAction {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { pinApp, deleteApp } from '../../../store/actions';
|
||||||
|
|
||||||
import classes from './AppTable.module.css';
|
import classes from './AppTable.module.css';
|
||||||
import Icon from '../../UI/Icons/Icon/Icon';
|
import Icon from '../../UI/Icons/Icon/Icon';
|
||||||
|
import Table from '../../UI/Table/Table';
|
||||||
|
|
||||||
interface ComponentProps {
|
interface ComponentProps {
|
||||||
apps: App[];
|
apps: App[];
|
||||||
|
@ -29,55 +30,48 @@ const AppTable = (props: ComponentProps): JSX.Element => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.TableContainer}>
|
<Table headers={[
|
||||||
<table className={classes.Table}>
|
'Name',
|
||||||
<thead className={classes.TableHead}>
|
'URL',
|
||||||
<tr>
|
'Icon',
|
||||||
<th>Name</th>
|
'Actions'
|
||||||
<th>Url</th>
|
]}>
|
||||||
<th>Icon</th>
|
{props.apps.map((app: App): JSX.Element => {
|
||||||
<th>Actions</th>
|
return (
|
||||||
|
<tr key={app.id}>
|
||||||
|
<td>{app.name}</td>
|
||||||
|
<td>{app.url}</td>
|
||||||
|
<td>{app.icon}</td>
|
||||||
|
<td className={classes.TableActions}>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
onClick={() => deleteAppHandler(app)}
|
||||||
|
onKeyDown={(e) => keyboardActionHandler(e, app, deleteAppHandler)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiDelete' />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
onClick={() => props.updateAppHandler(app)}
|
||||||
|
onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiPencil' />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
onClick={() => props.pinApp(app)}
|
||||||
|
onKeyDown={(e) => keyboardActionHandler(e, app, props.pinApp)}
|
||||||
|
tabIndex={0}>
|
||||||
|
{app.isPinned
|
||||||
|
? <Icon icon='mdiPinOff' color='var(--color-accent)' />
|
||||||
|
: <Icon icon='mdiPin' />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
)
|
||||||
<tbody className={classes.TableBody}>
|
})}
|
||||||
{props.apps.map((app: App): JSX.Element => {
|
</Table>
|
||||||
return (
|
|
||||||
<tr key={app.id}>
|
|
||||||
<td>{app.name}</td>
|
|
||||||
<td>{app.url}</td>
|
|
||||||
<td>{app.icon}</td>
|
|
||||||
<td className={classes.TableActions}>
|
|
||||||
<div
|
|
||||||
className={classes.TableAction}
|
|
||||||
onClick={() => deleteAppHandler(app)}
|
|
||||||
onKeyDown={(e) => keyboardActionHandler(e, app, deleteAppHandler)}
|
|
||||||
tabIndex={0}>
|
|
||||||
<Icon icon='mdiDelete' />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classes.TableAction}
|
|
||||||
onClick={() => props.updateAppHandler(app)}
|
|
||||||
onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
|
||||||
tabIndex={0}>
|
|
||||||
<Icon icon='mdiPencil' />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classes.TableAction}
|
|
||||||
onClick={() => props.pinApp(app)}
|
|
||||||
onKeyDown={(e) => keyboardActionHandler(e, app, props.pinApp)}
|
|
||||||
tabIndex={0}>
|
|
||||||
{app.isPinned
|
|
||||||
? <Icon icon='mdiPinOff' color='var(--color-accent)' />
|
|
||||||
: <Icon icon='mdiPin' />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@
|
||||||
transition: all 0.25s;
|
transition: all 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.BookmarkCard a:hover {
|
.BookmarkCard a:hover,
|
||||||
|
.BookmarkCard a:focus {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
|
@ -4,12 +4,12 @@ import { connect } from 'react-redux';
|
||||||
import ModalForm from '../../UI/Forms/ModalForm/ModalForm';
|
import ModalForm from '../../UI/Forms/ModalForm/ModalForm';
|
||||||
import InputGroup from '../../UI/Forms/InputGroup/InputGroup';
|
import InputGroup from '../../UI/Forms/InputGroup/InputGroup';
|
||||||
import { Category, GlobalState, NewBookmark, NewCategory } from '../../../interfaces';
|
import { Category, GlobalState, NewBookmark, NewCategory } from '../../../interfaces';
|
||||||
import { FormContentType } from '../Bookmarks';
|
import { ContentType } from '../Bookmarks';
|
||||||
import { getCategories, addCategory, addBookmark } from '../../../store/actions';
|
import { getCategories, addCategory, addBookmark } from '../../../store/actions';
|
||||||
|
|
||||||
interface ComponentProps {
|
interface ComponentProps {
|
||||||
modalHandler: () => void;
|
modalHandler: () => void;
|
||||||
contentType: FormContentType;
|
contentType: ContentType;
|
||||||
categories: Category[];
|
categories: Category[];
|
||||||
addCategory: (formData: NewCategory) => void;
|
addCategory: (formData: NewCategory) => void;
|
||||||
addBookmark: (formData: NewBookmark) => void;
|
addBookmark: (formData: NewBookmark) => void;
|
||||||
|
@ -29,10 +29,10 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
||||||
const formSubmitHandler = (e: SyntheticEvent<HTMLFormElement>): void => {
|
const formSubmitHandler = (e: SyntheticEvent<HTMLFormElement>): void => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (props.contentType === FormContentType.category) {
|
if (props.contentType === ContentType.category) {
|
||||||
props.addCategory(categoryName);
|
props.addCategory(categoryName);
|
||||||
setCategoryName({ name: '' });
|
setCategoryName({ name: '' });
|
||||||
} else if (props.contentType === FormContentType.bookmark) {
|
} else if (props.contentType === ContentType.bookmark) {
|
||||||
if (formData.categoryId === -1) {
|
if (formData.categoryId === -1) {
|
||||||
alert('select category');
|
alert('select category');
|
||||||
return;
|
return;
|
||||||
|
@ -66,7 +66,7 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
||||||
modalHandler={props.modalHandler}
|
modalHandler={props.modalHandler}
|
||||||
formHandler={formSubmitHandler}
|
formHandler={formSubmitHandler}
|
||||||
>
|
>
|
||||||
{props.contentType === FormContentType.category
|
{props.contentType === ContentType.category
|
||||||
? (
|
? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
.TableActions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TableAction {
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TableAction:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
103
client/src/components/Bookmarks/BookmarkTable/BookmarkTable.tsx
Normal file
103
client/src/components/Bookmarks/BookmarkTable/BookmarkTable.tsx
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
import { ContentType } from '../Bookmarks';
|
||||||
|
import classes from './BookmarkTable.module.css';
|
||||||
|
|
||||||
|
import Table from '../../UI/Table/Table';
|
||||||
|
import { Bookmark, Category } from '../../../interfaces';
|
||||||
|
import Icon from '../../UI/Icons/Icon/Icon';
|
||||||
|
|
||||||
|
interface ComponentProps {
|
||||||
|
contentType: ContentType;
|
||||||
|
categories: Category[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
||||||
|
if (props.contentType === ContentType.category) {
|
||||||
|
return (
|
||||||
|
<Table headers={[
|
||||||
|
'Name',
|
||||||
|
'Actions'
|
||||||
|
]}>
|
||||||
|
{props.categories.map((category: Category) => {
|
||||||
|
return (
|
||||||
|
<tr key={category.id}>
|
||||||
|
<td>{category.name}</td>
|
||||||
|
<td className={classes.TableActions}>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
// onClick={() => deleteAppHandler(app)}
|
||||||
|
// onKeyDown={(e) => keyboardActionHandler(e, app, deleteAppHandler)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiDelete' />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
// onClick={() => props.updateAppHandler(app)}
|
||||||
|
// onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiPencil' />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
// onClick={() => props.pinApp(app)}
|
||||||
|
// onKeyDown={(e) => keyboardActionHandler(e, app, props.pinApp)}
|
||||||
|
tabIndex={0}>
|
||||||
|
{category.isPinned
|
||||||
|
? <Icon icon='mdiPinOff' color='var(--color-accent)' />
|
||||||
|
: <Icon icon='mdiPin' />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Table>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
const bookmarks: {bookmark: Bookmark, categoryName: string}[] = [];
|
||||||
|
props.categories.forEach((category: Category) => {
|
||||||
|
category.bookmarks.forEach((bookmark: Bookmark) => {
|
||||||
|
bookmarks.push({
|
||||||
|
bookmark,
|
||||||
|
categoryName: category.name
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table headers={[
|
||||||
|
'Name',
|
||||||
|
'URL',
|
||||||
|
'Category',
|
||||||
|
'Actions'
|
||||||
|
]}>
|
||||||
|
{bookmarks.map((bookmark: {bookmark: Bookmark, categoryName: string}) => {
|
||||||
|
return (
|
||||||
|
<tr key={bookmark.bookmark.id}>
|
||||||
|
<td>{bookmark.bookmark.name}</td>
|
||||||
|
<td>{bookmark.bookmark.url}</td>
|
||||||
|
<td>{bookmark.categoryName}</td>
|
||||||
|
<td className={classes.TableActions}>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
// onClick={() => deleteAppHandler(app)}
|
||||||
|
// onKeyDown={(e) => keyboardActionHandler(e, app, deleteAppHandler)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiDelete' />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
// onClick={() => props.updateAppHandler(app)}
|
||||||
|
// onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiPencil' />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Table>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BookmarkTable;
|
|
@ -14,6 +14,7 @@ import { Category, GlobalState } from '../../interfaces';
|
||||||
import Spinner from '../UI/Spinner/Spinner';
|
import Spinner from '../UI/Spinner/Spinner';
|
||||||
import Modal from '../UI/Modal/Modal';
|
import Modal from '../UI/Modal/Modal';
|
||||||
import BookmarkForm from './BookmarkForm/BookmarkForm';
|
import BookmarkForm from './BookmarkForm/BookmarkForm';
|
||||||
|
import BookmarkTable from './BookmarkTable/BookmarkTable';
|
||||||
|
|
||||||
interface ComponentProps {
|
interface ComponentProps {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
@ -21,14 +22,16 @@ interface ComponentProps {
|
||||||
getCategories: () => void;
|
getCategories: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum FormContentType {
|
export enum ContentType {
|
||||||
category,
|
category,
|
||||||
bookmark
|
bookmark
|
||||||
}
|
}
|
||||||
|
|
||||||
const Bookmarks = (props: ComponentProps): JSX.Element => {
|
const Bookmarks = (props: ComponentProps): JSX.Element => {
|
||||||
const [modalIsOpen, setModalIsOpen] = useState(false);
|
const [modalIsOpen, setModalIsOpen] = useState(false);
|
||||||
const [formContentType, setFormContentType] = useState(FormContentType.category);
|
const [formContentType, setFormContentType] = useState(ContentType.category);
|
||||||
|
const [isInEdit, setIsInEdit] = useState(false);
|
||||||
|
const [tableContentType, setTableContentType] = useState(ContentType.category);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.categories.length === 0) {
|
if (props.categories.length === 0) {
|
||||||
|
@ -40,24 +43,29 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
|
||||||
setModalIsOpen(!modalIsOpen);
|
setModalIsOpen(!modalIsOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
const addActionHandler = (contentType: FormContentType) => {
|
const addActionHandler = (contentType: ContentType) => {
|
||||||
setFormContentType(contentType);
|
setFormContentType(contentType);
|
||||||
toggleModal();
|
toggleModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleEdit = (): void => {
|
||||||
|
setIsInEdit(!isInEdit);
|
||||||
|
}
|
||||||
|
|
||||||
|
const editActionHandler = (contentType: ContentType) => {
|
||||||
|
// We're in the edit mode and the same button was clicked - go back to list
|
||||||
|
if (isInEdit && contentType === tableContentType) {
|
||||||
|
setIsInEdit(false);
|
||||||
|
} else {
|
||||||
|
setIsInEdit(true);
|
||||||
|
setTableContentType(contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Modal isOpen={modalIsOpen} setIsOpen={toggleModal}>
|
<Modal isOpen={modalIsOpen} setIsOpen={toggleModal}>
|
||||||
{formContentType === FormContentType.category
|
<BookmarkForm modalHandler={toggleModal} contentType={formContentType} />
|
||||||
? <BookmarkForm
|
|
||||||
modalHandler={toggleModal}
|
|
||||||
contentType={FormContentType.category}
|
|
||||||
/>
|
|
||||||
: <BookmarkForm
|
|
||||||
modalHandler={toggleModal}
|
|
||||||
contentType={FormContentType.bookmark}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Headline
|
<Headline
|
||||||
|
@ -69,26 +77,30 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
|
||||||
<ActionButton
|
<ActionButton
|
||||||
name='Add Category'
|
name='Add Category'
|
||||||
icon='mdiPlusBox'
|
icon='mdiPlusBox'
|
||||||
handler={() => addActionHandler(FormContentType.category)}
|
handler={() => addActionHandler(ContentType.category)}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
name='Add Bookmark'
|
name='Add Bookmark'
|
||||||
icon='mdiPlusBox'
|
icon='mdiPlusBox'
|
||||||
handler={() => addActionHandler(FormContentType.bookmark)}
|
handler={() => addActionHandler(ContentType.bookmark)}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
name='Edit Categories'
|
name='Edit Categories'
|
||||||
icon='mdiPencil'
|
icon='mdiPencil'
|
||||||
|
handler={() => editActionHandler(ContentType.category)}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
name='Edit Bookmarks'
|
name='Edit Bookmarks'
|
||||||
icon='mdiPencil'
|
icon='mdiPencil'
|
||||||
|
handler={() => editActionHandler(ContentType.bookmark)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{props.loading
|
{props.loading
|
||||||
? <Spinner />
|
? <Spinner />
|
||||||
: <BookmarkGrid categories={props.categories} />
|
: (!isInEdit
|
||||||
|
? <BookmarkGrid categories={props.categories} />
|
||||||
|
: <BookmarkTable contentType={tableContentType} categories={props.categories} />)
|
||||||
}
|
}
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import classes from './Layout.module.css';
|
import classes from './Layout.module.css';
|
||||||
|
|
||||||
export const Container = (props: any): JSX.Element => {
|
interface ComponentProps {
|
||||||
|
children: JSX.Element | JSX.Element[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Container = (props: ComponentProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<div className={classes.Container}>
|
<div className={classes.Container}>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
41
client/src/components/UI/Table/Table.module.css
Normal file
41
client/src/components/UI/Table/Table.module.css
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
.TableContainer {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Table th,
|
||||||
|
.Table td {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Head */
|
||||||
|
|
||||||
|
.Table th {
|
||||||
|
--header-radius: 4px;
|
||||||
|
background-color: var(--color-primary);
|
||||||
|
color: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Table th:first-child {
|
||||||
|
border-top-left-radius: var(--header-radius);
|
||||||
|
border-bottom-left-radius: var(--header-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Table th:last-child {
|
||||||
|
border-top-right-radius: var(--header-radius);
|
||||||
|
border-bottom-right-radius: var(--header-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Body */
|
||||||
|
|
||||||
|
.Table td {
|
||||||
|
/* opacity: 0.5; */
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
25
client/src/components/UI/Table/Table.tsx
Normal file
25
client/src/components/UI/Table/Table.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import classes from './Table.module.css';
|
||||||
|
|
||||||
|
interface ComponentProps {
|
||||||
|
children: JSX.Element | JSX.Element[];
|
||||||
|
headers: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Table = (props: ComponentProps): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<div className={classes.TableContainer}>
|
||||||
|
<table className={classes.Table}>
|
||||||
|
<thead className={classes.TableHead}>
|
||||||
|
<tr>
|
||||||
|
{props.headers.map((header: string, index: number): JSX.Element => (<th key={index}>{header}</th>))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className={classes.TableBody}>
|
||||||
|
{props.children}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Table;
|
|
@ -2,7 +2,6 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
/* transition: all 0.3s; */
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,13 +13,6 @@ body {
|
||||||
|
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
transition: background-color 0.3s;
|
transition: background-color 0.3s;
|
||||||
/* font weights
|
|
||||||
light 300
|
|
||||||
regular 400
|
|
||||||
semi-bold 600
|
|
||||||
bold 700
|
|
||||||
extra-bold 800
|
|
||||||
*/
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, Roboto, sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
@ -28,11 +20,4 @@ body {
|
||||||
a {
|
a {
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
/* opacity: 0.75; */
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* 320px — 480px: Mobile devices.
|
|
||||||
481px — 768px: iPads, Tablets.
|
|
||||||
769px — 1024px: Small screens, laptops.
|
|
||||||
1025px — 1200px: Desktops, large screens.
|
|
||||||
1201px and more — Extra large screens, TV. */
|
|
|
@ -2,6 +2,7 @@ import axios from 'axios';
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { ActionTypes } from './actionTypes';
|
import { ActionTypes } from './actionTypes';
|
||||||
import { Category, ApiResponse, NewCategory, Bookmark, NewBookmark } from '../../interfaces';
|
import { Category, ApiResponse, NewCategory, Bookmark, NewBookmark } from '../../interfaces';
|
||||||
|
import { CreateNotificationAction } from './notification';
|
||||||
|
|
||||||
export interface GetCategoriesAction<T> {
|
export interface GetCategoriesAction<T> {
|
||||||
type: ActionTypes.getCategories | ActionTypes.getCategoriesSuccess | ActionTypes.getCategoriesError;
|
type: ActionTypes.getCategories | ActionTypes.getCategoriesSuccess | ActionTypes.getCategoriesError;
|
||||||
|
@ -35,6 +36,14 @@ export const addCategory = (formData: NewCategory) => async (dispatch: Dispatch)
|
||||||
try {
|
try {
|
||||||
const res = await axios.post<ApiResponse<Category>>('/api/categories', formData);
|
const res = await axios.post<ApiResponse<Category>>('/api/categories', formData);
|
||||||
|
|
||||||
|
dispatch<CreateNotificationAction>({
|
||||||
|
type: ActionTypes.createNotification,
|
||||||
|
payload: {
|
||||||
|
title: 'Success',
|
||||||
|
message: `Category ${formData.name} created`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
dispatch<AddCategoryAction>({
|
dispatch<AddCategoryAction>({
|
||||||
type: ActionTypes.addCategory,
|
type: ActionTypes.addCategory,
|
||||||
payload: res.data.data
|
payload: res.data.data
|
||||||
|
@ -53,6 +62,14 @@ export const addBookmark = (formData: NewBookmark) => async (dispatch: Dispatch)
|
||||||
try {
|
try {
|
||||||
const res = await axios.post<ApiResponse<Bookmark>>('/api/bookmarks', formData);
|
const res = await axios.post<ApiResponse<Bookmark>>('/api/bookmarks', formData);
|
||||||
|
|
||||||
|
dispatch<CreateNotificationAction>({
|
||||||
|
type: ActionTypes.createNotification,
|
||||||
|
payload: {
|
||||||
|
title: 'Success',
|
||||||
|
message: `Bookmark ${formData.name} created`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
dispatch<AddBookmarkAction>({
|
dispatch<AddBookmarkAction>({
|
||||||
type: ActionTypes.addBookmark,
|
type: ActionTypes.addBookmark,
|
||||||
payload: res.data.data
|
payload: res.data.data
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue