mirror of
https://github.com/pawelmalak/flame.git
synced 2025-07-22 21:09:36 +02:00
Updating categories using form
This commit is contained in:
parent
0f2125e720
commit
216c12a33c
11 changed files with 176 additions and 30 deletions
|
@ -5,6 +5,7 @@ import { App, NewApp } from '../../../interfaces';
|
||||||
|
|
||||||
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 Button from '../../UI/Buttons/Button/Button';
|
||||||
|
|
||||||
interface ComponentProps {
|
interface ComponentProps {
|
||||||
modalHandler: () => void;
|
modalHandler: () => void;
|
||||||
|
@ -35,6 +36,12 @@ const AppForm = (props: ComponentProps): JSX.Element => {
|
||||||
url: props.app.url,
|
url: props.app.url,
|
||||||
icon: props.app.icon
|
icon: props.app.icon
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
setFormData({
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
icon: ''
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, [props.app])
|
}, [props.app])
|
||||||
|
|
||||||
|
@ -114,8 +121,8 @@ const AppForm = (props: ComponentProps): JSX.Element => {
|
||||||
</span>
|
</span>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
{!props.app
|
{!props.app
|
||||||
? <button type="submit">add</button>
|
? <Button>Add new application</Button>
|
||||||
: <button type="submit">update</button>
|
: <Button>Update application</Button>
|
||||||
}
|
}
|
||||||
</ModalForm>
|
</ModalForm>
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,8 +21,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 320px — 480px: Mobile devices.
|
.GridMessage {
|
||||||
481px — 768px: iPads, Tablets.
|
color: var(--color-primary);
|
||||||
769px — 1024px: Small screens, laptops.
|
}
|
||||||
1025px — 1200px: Desktops, large screens.
|
|
||||||
1201px and more — Extra large screens, TV. */
|
.GridMessage a {
|
||||||
|
color: var(--color-accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
|
@ -104,7 +104,7 @@ const Apps = (props: ComponentProps): JSX.Element => {
|
||||||
: (!isInEdit
|
: (!isInEdit
|
||||||
? props.apps.length > 0
|
? props.apps.length > 0
|
||||||
? <AppGrid apps={props.apps} />
|
? <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} />)
|
: <AppTable updateAppHandler={toggleUpdate} />)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,16 +3,20 @@ 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, NewNotification } from '../../../interfaces';
|
||||||
import { ContentType } from '../Bookmarks';
|
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 {
|
interface ComponentProps {
|
||||||
modalHandler: () => void;
|
modalHandler: () => void;
|
||||||
contentType: ContentType;
|
contentType: ContentType;
|
||||||
categories: Category[];
|
categories: Category[];
|
||||||
|
category?: Category;
|
||||||
addCategory: (formData: NewCategory) => void;
|
addCategory: (formData: NewCategory) => void;
|
||||||
addBookmark: (formData: NewBookmark) => void;
|
addBookmark: (formData: NewBookmark) => void;
|
||||||
|
updateCategory: (id: number, formData: NewCategory) => void;
|
||||||
|
createNotification: (notification: NewNotification) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
||||||
|
@ -26,15 +30,28 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
||||||
categoryId: -1
|
categoryId: -1
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.category) {
|
||||||
|
setCategoryName({ name: props.category.name });
|
||||||
|
} else {
|
||||||
|
setCategoryName({ name: '' });
|
||||||
|
}
|
||||||
|
}, [props.category])
|
||||||
|
|
||||||
const formSubmitHandler = (e: SyntheticEvent<HTMLFormElement>): void => {
|
const formSubmitHandler = (e: SyntheticEvent<HTMLFormElement>): void => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!props.category) {
|
||||||
|
// Add new
|
||||||
if (props.contentType === ContentType.category) {
|
if (props.contentType === ContentType.category) {
|
||||||
props.addCategory(categoryName);
|
props.addCategory(categoryName);
|
||||||
setCategoryName({ name: '' });
|
setCategoryName({ name: '' });
|
||||||
} else if (props.contentType === ContentType.bookmark) {
|
} else if (props.contentType === ContentType.bookmark) {
|
||||||
if (formData.categoryId === -1) {
|
if (formData.categoryId === -1) {
|
||||||
alert('select category');
|
props.createNotification({
|
||||||
|
title: 'Error',
|
||||||
|
message: 'Please select category'
|
||||||
|
})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +62,15 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
||||||
categoryId: formData.categoryId
|
categoryId: formData.categoryId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Update
|
||||||
|
if (props.contentType === ContentType.category) {
|
||||||
|
props.updateCategory(props.category.id, categoryName);
|
||||||
|
setCategoryName({ name: '' });
|
||||||
|
}
|
||||||
|
|
||||||
|
props.modalHandler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const inputChangeHandler = (e: ChangeEvent<HTMLInputElement>): void => {
|
const inputChangeHandler = (e: ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
@ -133,7 +159,10 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<button type='submit'>add</button>
|
{!props.category
|
||||||
|
? <Button>Add new category</Button>
|
||||||
|
: <Button>Update category</Button>
|
||||||
|
}
|
||||||
</ModalForm>
|
</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);
|
|
@ -13,6 +13,7 @@ interface ComponentProps {
|
||||||
categories: Category[];
|
categories: Category[];
|
||||||
pinCategory: (category: Category) => void;
|
pinCategory: (category: Category) => void;
|
||||||
deleteCategory: (id: number) => void;
|
deleteCategory: (id: number) => void;
|
||||||
|
updateCategoryHandler: (category: Category) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
||||||
|
@ -50,7 +51,7 @@ const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classes.TableAction}
|
className={classes.TableAction}
|
||||||
// onClick={() => props.updateAppHandler(app)}
|
onClick={() => props.updateCategoryHandler(category)}
|
||||||
// onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
// onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
||||||
tabIndex={0}>
|
tabIndex={0}>
|
||||||
<Icon icon='mdiPencil' />
|
<Icon icon='mdiPencil' />
|
||||||
|
|
|
@ -32,6 +32,15 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
|
||||||
const [formContentType, setFormContentType] = useState(ContentType.category);
|
const [formContentType, setFormContentType] = useState(ContentType.category);
|
||||||
const [isInEdit, setIsInEdit] = useState(false);
|
const [isInEdit, setIsInEdit] = useState(false);
|
||||||
const [tableContentType, setTableContentType] = useState(ContentType.category);
|
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(() => {
|
useEffect(() => {
|
||||||
if (props.categories.length === 0) {
|
if (props.categories.length === 0) {
|
||||||
|
@ -45,6 +54,7 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
|
||||||
|
|
||||||
const addActionHandler = (contentType: ContentType) => {
|
const addActionHandler = (contentType: ContentType) => {
|
||||||
setFormContentType(contentType);
|
setFormContentType(contentType);
|
||||||
|
setIsInUpdate(false);
|
||||||
toggleModal();
|
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 (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Modal isOpen={modalIsOpen} setIsOpen={toggleModal}>
|
<Modal isOpen={modalIsOpen} setIsOpen={toggleModal}>
|
||||||
<BookmarkForm modalHandler={toggleModal} contentType={formContentType} />
|
{!isInUpdate
|
||||||
|
? <BookmarkForm modalHandler={toggleModal} contentType={formContentType} />
|
||||||
|
: <BookmarkForm modalHandler={toggleModal} contentType={formContentType} category={categoryInUpdate} />
|
||||||
|
}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Headline
|
<Headline
|
||||||
|
@ -101,8 +122,13 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
|
||||||
: (!isInEdit
|
: (!isInEdit
|
||||||
? props.categories.length > 0
|
? props.categories.length > 0
|
||||||
? <BookmarkGrid categories={props.categories} />
|
? <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>
|
: <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} />)
|
: (<BookmarkTable
|
||||||
|
contentType={tableContentType}
|
||||||
|
categories={props.categories}
|
||||||
|
updateCategoryHandler={goToUpdateMode}
|
||||||
|
/>)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|
14
client/src/components/UI/Buttons/Button/Button.module.css
Normal file
14
client/src/components/UI/Buttons/Button/Button.module.css
Normal 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);
|
||||||
|
}
|
11
client/src/components/UI/Buttons/Button/Button.tsx
Normal file
11
client/src/components/UI/Buttons/Button/Button.tsx
Normal 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;
|
|
@ -13,6 +13,7 @@ import {
|
||||||
AddBookmarkAction,
|
AddBookmarkAction,
|
||||||
PinCategoryAction,
|
PinCategoryAction,
|
||||||
DeleteCategoryAction,
|
DeleteCategoryAction,
|
||||||
|
UpdateCategoryAction,
|
||||||
// Notifications
|
// Notifications
|
||||||
CreateNotificationAction,
|
CreateNotificationAction,
|
||||||
ClearNotificationAction
|
ClearNotificationAction
|
||||||
|
@ -38,6 +39,7 @@ export enum ActionTypes {
|
||||||
addBookmark = 'ADD_BOOKMARK',
|
addBookmark = 'ADD_BOOKMARK',
|
||||||
pinCategory = 'PIN_CATEGORY',
|
pinCategory = 'PIN_CATEGORY',
|
||||||
deleteCategory = 'DELETE_CATEGORY',
|
deleteCategory = 'DELETE_CATEGORY',
|
||||||
|
updateCategory = 'UPDATE_CATEGORY',
|
||||||
// Notifications
|
// Notifications
|
||||||
createNotification = 'CREATE_NOTIFICATION',
|
createNotification = 'CREATE_NOTIFICATION',
|
||||||
clearNotification = 'CLEAR_NOTIFICATION'
|
clearNotification = 'CLEAR_NOTIFICATION'
|
||||||
|
@ -58,6 +60,7 @@ export type Action =
|
||||||
AddBookmarkAction |
|
AddBookmarkAction |
|
||||||
PinCategoryAction |
|
PinCategoryAction |
|
||||||
DeleteCategoryAction |
|
DeleteCategoryAction |
|
||||||
|
UpdateCategoryAction |
|
||||||
// Notifications
|
// Notifications
|
||||||
CreateNotificationAction |
|
CreateNotificationAction |
|
||||||
ClearNotificationAction;
|
ClearNotificationAction;
|
|
@ -148,3 +148,32 @@ export const deleteCategory = (id: number) => async (dispatch: Dispatch) => {
|
||||||
console.log(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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) => {
|
const bookmarkReducer = (state = initialState, action: Action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ActionTypes.getCategories: return getCategories(state, action);
|
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.addBookmark: return addBookmark(state, action);
|
||||||
case ActionTypes.pinCategory: return pinCategory(state, action);
|
case ActionTypes.pinCategory: return pinCategory(state, action);
|
||||||
case ActionTypes.deleteCategory: return deleteCategory(state, action);
|
case ActionTypes.deleteCategory: return deleteCategory(state, action);
|
||||||
|
case ActionTypes.updateCategory: return updateCategory(state, action);
|
||||||
default: return state;
|
default: return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue