Updating categories using form

This commit is contained in:
unknown 2021-05-26 13:13:56 +02:00
parent 0f2125e720
commit 216c12a33c
11 changed files with 176 additions and 30 deletions

View file

@ -5,6 +5,7 @@ import { App, NewApp } from '../../../interfaces';
import ModalForm from '../../UI/Forms/ModalForm/ModalForm';
import InputGroup from '../../UI/Forms/InputGroup/InputGroup';
import Button from '../../UI/Buttons/Button/Button';
interface ComponentProps {
modalHandler: () => void;
@ -35,6 +36,12 @@ const AppForm = (props: ComponentProps): JSX.Element => {
url: props.app.url,
icon: props.app.icon
})
} else {
setFormData({
name: '',
url: '',
icon: ''
})
}
}, [props.app])
@ -114,8 +121,8 @@ const AppForm = (props: ComponentProps): JSX.Element => {
</span>
</InputGroup>
{!props.app
? <button type="submit">add</button>
: <button type="submit">update</button>
? <Button>Add new application</Button>
: <Button>Update application</Button>
}
</ModalForm>
)

View file

@ -21,8 +21,11 @@
}
}
/* 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. */
.GridMessage {
color: var(--color-primary);
}
.GridMessage a {
color: var(--color-accent);
font-weight: 600;
}

View file

@ -104,7 +104,7 @@ const Apps = (props: ComponentProps): JSX.Element => {
: (!isInEdit
? props.apps.length > 0
? <AppGrid apps={props.apps} />
: <p className={classes.AppsMessage}>You don't have any applications. You can a new one from <Link to='/applications'>/application</Link> menu</p>
: <p className={classes.AppsMessage}>You don't have any applications. You can add a new one from <Link to='/applications'>/application</Link> menu</p>
: <AppTable updateAppHandler={toggleUpdate} />)
}
</div>

View file

@ -3,16 +3,20 @@ import { connect } from 'react-redux';
import ModalForm from '../../UI/Forms/ModalForm/ModalForm';
import InputGroup from '../../UI/Forms/InputGroup/InputGroup';
import { Category, GlobalState, NewBookmark, NewCategory } from '../../../interfaces';
import { Category, GlobalState, NewBookmark, NewCategory, NewNotification } from '../../../interfaces';
import { ContentType } from '../Bookmarks';
import { getCategories, addCategory, addBookmark } from '../../../store/actions';
import { getCategories, addCategory, addBookmark, updateCategory, createNotification } from '../../../store/actions';
import Button from '../../UI/Buttons/Button/Button';
interface ComponentProps {
modalHandler: () => void;
contentType: ContentType;
categories: Category[];
category?: Category;
addCategory: (formData: NewCategory) => void;
addBookmark: (formData: NewBookmark) => void;
updateCategory: (id: number, formData: NewCategory) => void;
createNotification: (notification: NewNotification) => void;
}
const BookmarkForm = (props: ComponentProps): JSX.Element => {
@ -26,24 +30,46 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
categoryId: -1
})
useEffect(() => {
if (props.category) {
setCategoryName({ name: props.category.name });
} else {
setCategoryName({ name: '' });
}
}, [props.category])
const formSubmitHandler = (e: SyntheticEvent<HTMLFormElement>): void => {
e.preventDefault();
if (props.contentType === ContentType.category) {
props.addCategory(categoryName);
setCategoryName({ name: '' });
} else if (props.contentType === ContentType.bookmark) {
if (formData.categoryId === -1) {
alert('select category');
return;
if (!props.category) {
// Add new
if (props.contentType === ContentType.category) {
props.addCategory(categoryName);
setCategoryName({ name: '' });
} else if (props.contentType === ContentType.bookmark) {
if (formData.categoryId === -1) {
props.createNotification({
title: 'Error',
message: 'Please select category'
})
return;
}
props.addBookmark(formData);
setFormData({
name: '',
url: '',
categoryId: formData.categoryId
})
}
} else {
// Update
if (props.contentType === ContentType.category) {
props.updateCategory(props.category.id, categoryName);
setCategoryName({ name: '' });
}
props.addBookmark(formData);
setFormData({
name: '',
url: '',
categoryId: formData.categoryId
})
props.modalHandler();
}
}
@ -133,7 +159,10 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
</Fragment>
)
}
<button type='submit'>add</button>
{!props.category
? <Button>Add new category</Button>
: <Button>Update category</Button>
}
</ModalForm>
)
}
@ -144,4 +173,12 @@ const mapStateToProps = (state: GlobalState) => {
}
}
export default connect(mapStateToProps, { getCategories, addCategory, addBookmark })(BookmarkForm);
const dispatchMap = {
getCategories,
addCategory,
addBookmark,
updateCategory,
createNotification
}
export default connect(mapStateToProps, dispatchMap)(BookmarkForm);

View file

@ -13,6 +13,7 @@ interface ComponentProps {
categories: Category[];
pinCategory: (category: Category) => void;
deleteCategory: (id: number) => void;
updateCategoryHandler: (category: Category) => void;
}
const BookmarkTable = (props: ComponentProps): JSX.Element => {
@ -50,7 +51,7 @@ const BookmarkTable = (props: ComponentProps): JSX.Element => {
</div>
<div
className={classes.TableAction}
// onClick={() => props.updateAppHandler(app)}
onClick={() => props.updateCategoryHandler(category)}
// onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
tabIndex={0}>
<Icon icon='mdiPencil' />

View file

@ -32,6 +32,15 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
const [formContentType, setFormContentType] = useState(ContentType.category);
const [isInEdit, setIsInEdit] = useState(false);
const [tableContentType, setTableContentType] = useState(ContentType.category);
const [isInUpdate, setIsInUpdate] = useState(false);
const [categoryInUpdate, setCategoryInUpdate] = useState<Category>({
name: '',
id: -1,
isPinned: false,
bookmarks: [],
createdAt: new Date(),
updatedAt: new Date()
})
useEffect(() => {
if (props.categories.length === 0) {
@ -45,6 +54,7 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
const addActionHandler = (contentType: ContentType) => {
setFormContentType(contentType);
setIsInUpdate(false);
toggleModal();
}
@ -62,10 +72,21 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
}
}
const goToUpdateMode = (category: Category): void => {
setIsInUpdate(true);
setCategoryInUpdate(category);
toggleModal();
}
let modalForm: JSX.Element;
return (
<Container>
<Modal isOpen={modalIsOpen} setIsOpen={toggleModal}>
<BookmarkForm modalHandler={toggleModal} contentType={formContentType} />
{!isInUpdate
? <BookmarkForm modalHandler={toggleModal} contentType={formContentType} />
: <BookmarkForm modalHandler={toggleModal} contentType={formContentType} category={categoryInUpdate} />
}
</Modal>
<Headline
@ -101,8 +122,13 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
: (!isInEdit
? props.categories.length > 0
? <BookmarkGrid categories={props.categories} />
: <p className={classes.BookmarksMessage}>You don't have any bookmarks. You can a new one from <Link to='/bookmarks'>/bookmarks</Link> menu</p>
: <BookmarkTable contentType={tableContentType} categories={props.categories} />)
: <p className={classes.BookmarksMessage}>You don't have any bookmarks. You can add a new one from <Link to='/bookmarks'>/bookmarks</Link> menu</p>
: (<BookmarkTable
contentType={tableContentType}
categories={props.categories}
updateCategoryHandler={goToUpdateMode}
/>)
)
}
</Container>
)

View file

@ -0,0 +1,14 @@
.Button {
padding: 8px 15px;
border: 1px solid var(--color-accent);
background-color: var(--color-background);
color: var(--color-primary);
border-radius: 4px;
}
.Button:hover,
.Button:focus {
cursor: pointer;
background-color: var(--color-accent);
color: var(--color-background);
}

View file

@ -0,0 +1,11 @@
import classes from './Button.module.css';
interface ComponentProps {
children: string;
}
const Button = (props: ComponentProps): JSX.Element => {
return <button className={classes.Button}>{props.children}</button>
}
export default Button;

View file

@ -13,6 +13,7 @@ import {
AddBookmarkAction,
PinCategoryAction,
DeleteCategoryAction,
UpdateCategoryAction,
// Notifications
CreateNotificationAction,
ClearNotificationAction
@ -38,6 +39,7 @@ export enum ActionTypes {
addBookmark = 'ADD_BOOKMARK',
pinCategory = 'PIN_CATEGORY',
deleteCategory = 'DELETE_CATEGORY',
updateCategory = 'UPDATE_CATEGORY',
// Notifications
createNotification = 'CREATE_NOTIFICATION',
clearNotification = 'CLEAR_NOTIFICATION'
@ -58,6 +60,7 @@ export type Action =
AddBookmarkAction |
PinCategoryAction |
DeleteCategoryAction |
UpdateCategoryAction |
// Notifications
CreateNotificationAction |
ClearNotificationAction;

View file

@ -147,4 +147,33 @@ export const deleteCategory = (id: number) => async (dispatch: Dispatch) => {
} catch (err) {
console.log(err);
}
}
/**
* UPDATE CATEGORY
*/
export interface UpdateCategoryAction {
type: ActionTypes.updateCategory,
payload: Category
}
export const updateCategory = (id: number, formData: NewCategory) => async (dispatch: Dispatch) => {
try {
const res = await axios.put<ApiResponse<Category>>(`/api/categories/${id}`, formData);
dispatch<CreateNotificationAction>({
type: ActionTypes.createNotification,
payload: {
title: 'Success',
message: `Category ${formData.name} updated`
}
})
dispatch<UpdateCategoryAction>({
type: ActionTypes.updateCategory,
payload: res.data.data
})
} catch (err) {
console.log(err);
}
}

View file

@ -78,6 +78,20 @@ const deleteCategory = (state: State, action: Action): State => {
}
}
const updateCategory = (state: State, action: Action): State => {
const tmpCategories = [...state.categories];
const categoryInUpdate = tmpCategories.find((category: Category) => category.id === action.payload.id);
if (categoryInUpdate) {
categoryInUpdate.name = action.payload.name;
}
return {
...state,
categories: tmpCategories
}
}
const bookmarkReducer = (state = initialState, action: Action) => {
switch (action.type) {
case ActionTypes.getCategories: return getCategories(state, action);
@ -86,6 +100,7 @@ const bookmarkReducer = (state = initialState, action: Action) => {
case ActionTypes.addBookmark: return addBookmark(state, action);
case ActionTypes.pinCategory: return pinCategory(state, action);
case ActionTypes.deleteCategory: return deleteCategory(state, action);
case ActionTypes.updateCategory: return updateCategory(state, action);
default: return state;
}
}