mirror of
https://github.com/pawelmalak/flame.git
synced 2024-12-26 03:56:55 +03:00
Sorting and custom ordering for categories
This commit is contained in:
parent
5b900872af
commit
ae3141e37b
@ -1 +1 @@
|
|||||||
REACT_APP_VERSION=1.3.6
|
REACT_APP_VERSION=1.3.7
|
@ -9,4 +9,21 @@
|
|||||||
|
|
||||||
.TableAction:hover {
|
.TableAction:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Message {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: baseline;
|
||||||
|
color: var(--color-primary);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Message a {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Message a:hover {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
@ -1,13 +1,25 @@
|
|||||||
import { ContentType } from '../Bookmarks';
|
import { KeyboardEvent, useState, useEffect, Fragment } from 'react';
|
||||||
import classes from './BookmarkTable.module.css';
|
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
|
||||||
import { connect } from 'react-redux';
|
import { Link } from 'react-router-dom';
|
||||||
import { pinCategory, deleteCategory, deleteBookmark } from '../../../store/actions';
|
|
||||||
import { KeyboardEvent } from 'react';
|
|
||||||
|
|
||||||
|
// Redux
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { pinCategory, deleteCategory, deleteBookmark, createNotification, reorderCategories } from '../../../store/actions';
|
||||||
|
|
||||||
|
// Typescript
|
||||||
|
import { Bookmark, Category, NewNotification } from '../../../interfaces';
|
||||||
|
import { ContentType } from '../Bookmarks';
|
||||||
|
|
||||||
|
// CSS
|
||||||
|
import classes from './BookmarkTable.module.css';
|
||||||
|
|
||||||
|
// UI
|
||||||
import Table from '../../UI/Table/Table';
|
import Table from '../../UI/Table/Table';
|
||||||
import { Bookmark, Category } from '../../../interfaces';
|
|
||||||
import Icon from '../../UI/Icons/Icon/Icon';
|
import Icon from '../../UI/Icons/Icon/Icon';
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
import { searchConfig } from '../../../utility';
|
||||||
|
|
||||||
interface ComponentProps {
|
interface ComponentProps {
|
||||||
contentType: ContentType;
|
contentType: ContentType;
|
||||||
categories: Category[];
|
categories: Category[];
|
||||||
@ -15,9 +27,28 @@ interface ComponentProps {
|
|||||||
deleteCategory: (id: number) => void;
|
deleteCategory: (id: number) => void;
|
||||||
updateHandler: (data: Category | Bookmark) => void;
|
updateHandler: (data: Category | Bookmark) => void;
|
||||||
deleteBookmark: (bookmarkId: number, categoryId: number) => void;
|
deleteBookmark: (bookmarkId: number, categoryId: number) => void;
|
||||||
|
createNotification: (notification: NewNotification) => void;
|
||||||
|
reorderCategories: (categories: Category[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
||||||
|
const [localCategories, setLocalCategories] = useState<Category[]>([]);
|
||||||
|
const [isCustomOrder, setIsCustomOrder] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// Copy categories array
|
||||||
|
useEffect(() => {
|
||||||
|
setLocalCategories([...props.categories]);
|
||||||
|
}, [props.categories])
|
||||||
|
|
||||||
|
// Check ordering
|
||||||
|
useEffect(() => {
|
||||||
|
const order = searchConfig('useOrdering', '');
|
||||||
|
|
||||||
|
if (order === 'orderId') {
|
||||||
|
setIsCustomOrder(true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const deleteCategoryHandler = (category: Category): void => {
|
const deleteCategoryHandler = (category: Category): void => {
|
||||||
const proceed = window.confirm(`Are you sure you want to delete ${category.name}? It will delete ALL assigned bookmarks`);
|
const proceed = window.confirm(`Are you sure you want to delete ${category.name}? It will delete ALL assigned bookmarks`);
|
||||||
|
|
||||||
@ -40,46 +71,100 @@ const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dragEndHanlder = (result: DropResult): void => {
|
||||||
|
if (!isCustomOrder) {
|
||||||
|
props.createNotification({
|
||||||
|
title: 'Error',
|
||||||
|
message: 'Custom order is disabled'
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.destination) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tmpCategories = [...localCategories];
|
||||||
|
const [movedApp] = tmpCategories.splice(result.source.index, 1);
|
||||||
|
tmpCategories.splice(result.destination.index, 0, movedApp);
|
||||||
|
|
||||||
|
setLocalCategories(tmpCategories);
|
||||||
|
props.reorderCategories(tmpCategories);
|
||||||
|
}
|
||||||
|
|
||||||
if (props.contentType === ContentType.category) {
|
if (props.contentType === ContentType.category) {
|
||||||
return (
|
return (
|
||||||
<Table headers={[
|
<Fragment>
|
||||||
'Name',
|
<div className={classes.Message}>
|
||||||
'Actions'
|
{isCustomOrder
|
||||||
]}>
|
? <p>You can drag and drop single rows to reorder categories</p>
|
||||||
{props.categories.map((category: Category) => {
|
: <p>Custom order is disabled. You can change it in <Link to='/settings/other'>settings</Link></p>
|
||||||
return (
|
}
|
||||||
<tr key={category.id}>
|
</div>
|
||||||
<td>{category.name}</td>
|
<DragDropContext onDragEnd={dragEndHanlder}>
|
||||||
<td className={classes.TableActions}>
|
<Droppable droppableId='categories'>
|
||||||
<div
|
{(provided) => (
|
||||||
className={classes.TableAction}
|
<Table headers={[
|
||||||
onClick={() => deleteCategoryHandler(category)}
|
'Name',
|
||||||
onKeyDown={(e) => keyboardActionHandler(e, category, deleteCategoryHandler)}
|
'Actions'
|
||||||
tabIndex={0}>
|
]}
|
||||||
<Icon icon='mdiDelete' />
|
innerRef={provided.innerRef}>
|
||||||
</div>
|
{localCategories.map((category: Category, index): JSX.Element => {
|
||||||
<div
|
return (
|
||||||
className={classes.TableAction}
|
<Draggable key={category.id} draggableId={category.id.toString()} index={index}>
|
||||||
onClick={() => props.updateHandler(category)}
|
{(provided, snapshot) => {
|
||||||
// onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
const style = {
|
||||||
tabIndex={0}>
|
border: snapshot.isDragging ? '1px solid var(--color-accent)' : 'none',
|
||||||
<Icon icon='mdiPencil' />
|
borderRadius: '4px',
|
||||||
</div>
|
...provided.draggableProps.style,
|
||||||
<div
|
};
|
||||||
className={classes.TableAction}
|
|
||||||
onClick={() => props.pinCategory(category)}
|
return (
|
||||||
onKeyDown={(e) => keyboardActionHandler(e, category, props.pinCategory)}
|
<tr
|
||||||
tabIndex={0}>
|
{...provided.draggableProps}
|
||||||
{category.isPinned
|
{...provided.dragHandleProps}
|
||||||
? <Icon icon='mdiPinOff' color='var(--color-accent)' />
|
ref={provided.innerRef}
|
||||||
: <Icon icon='mdiPin' />
|
style={style}
|
||||||
}
|
>
|
||||||
</div>
|
<td>{category.name}</td>
|
||||||
</td>
|
{!snapshot.isDragging && (
|
||||||
</tr>
|
<td className={classes.TableActions}>
|
||||||
)
|
<div
|
||||||
})}
|
className={classes.TableAction}
|
||||||
</Table>
|
onClick={() => deleteCategoryHandler(category)}
|
||||||
|
onKeyDown={(e) => keyboardActionHandler(e, category, deleteCategoryHandler)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiDelete' />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
onClick={() => props.updateHandler(category)}
|
||||||
|
tabIndex={0}>
|
||||||
|
<Icon icon='mdiPencil' />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classes.TableAction}
|
||||||
|
onClick={() => props.pinCategory(category)}
|
||||||
|
onKeyDown={(e) => keyboardActionHandler(e, category, props.pinCategory)}
|
||||||
|
tabIndex={0}>
|
||||||
|
{category.isPinned
|
||||||
|
? <Icon icon='mdiPinOff' color='var(--color-accent)' />
|
||||||
|
: <Icon icon='mdiPin' />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
)}
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</Draggable>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Table>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
|
</Fragment>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
const bookmarks: {bookmark: Bookmark, categoryName: string}[] = [];
|
const bookmarks: {bookmark: Bookmark, categoryName: string}[] = [];
|
||||||
@ -111,14 +196,12 @@ const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
|||||||
<div
|
<div
|
||||||
className={classes.TableAction}
|
className={classes.TableAction}
|
||||||
onClick={() => deleteBookmarkHandler(bookmark.bookmark)}
|
onClick={() => deleteBookmarkHandler(bookmark.bookmark)}
|
||||||
// onKeyDown={(e) => keyboardActionHandler(e, app, deleteAppHandler)}
|
|
||||||
tabIndex={0}>
|
tabIndex={0}>
|
||||||
<Icon icon='mdiDelete' />
|
<Icon icon='mdiDelete' />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classes.TableAction}
|
className={classes.TableAction}
|
||||||
onClick={() => props.updateHandler(bookmark.bookmark)}
|
onClick={() => props.updateHandler(bookmark.bookmark)}
|
||||||
// onKeyDown={(e) => keyboardActionHandler(e, app, props.updateAppHandler)}
|
|
||||||
tabIndex={0}>
|
tabIndex={0}>
|
||||||
<Icon icon='mdiPencil' />
|
<Icon icon='mdiPencil' />
|
||||||
</div>
|
</div>
|
||||||
@ -131,4 +214,12 @@ const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(null, { pinCategory, deleteCategory, deleteBookmark })(BookmarkTable);
|
const actions = {
|
||||||
|
pinCategory,
|
||||||
|
deleteCategory,
|
||||||
|
deleteBookmark,
|
||||||
|
createNotification,
|
||||||
|
reorderCategories
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(null, actions)(BookmarkTable);
|
@ -43,6 +43,7 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
|
|||||||
name: '',
|
name: '',
|
||||||
id: -1,
|
id: -1,
|
||||||
isPinned: false,
|
isPinned: false,
|
||||||
|
orderId: 0,
|
||||||
bookmarks: [],
|
bookmarks: [],
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
|
@ -2,7 +2,7 @@ import { useState, useEffect, ChangeEvent, FormEvent } from 'react';
|
|||||||
|
|
||||||
// Redux
|
// Redux
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createNotification, updateConfig, sortApps } from '../../../store/actions';
|
import { createNotification, updateConfig, sortApps, sortCategories } from '../../../store/actions';
|
||||||
|
|
||||||
// Typescript
|
// Typescript
|
||||||
import { GlobalState, NewNotification, SettingsForm } from '../../../interfaces';
|
import { GlobalState, NewNotification, SettingsForm } from '../../../interfaces';
|
||||||
@ -18,6 +18,7 @@ interface ComponentProps {
|
|||||||
createNotification: (notification: NewNotification) => void;
|
createNotification: (notification: NewNotification) => void;
|
||||||
updateConfig: (formData: SettingsForm) => void;
|
updateConfig: (formData: SettingsForm) => void;
|
||||||
sortApps: () => void;
|
sortApps: () => void;
|
||||||
|
sortCategories: () => void;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,8 +53,9 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
|||||||
// Update local page title
|
// Update local page title
|
||||||
document.title = formData.customTitle;
|
document.title = formData.customTitle;
|
||||||
|
|
||||||
// Get sorted apps
|
// Sort apps and categories with new settings
|
||||||
props.sortApps();
|
props.sortApps();
|
||||||
|
props.sortCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input handler
|
// Input handler
|
||||||
@ -143,4 +145,11 @@ const mapStateToProps = (state: GlobalState) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, { createNotification, updateConfig, sortApps })(OtherSettings);
|
const actions = {
|
||||||
|
createNotification,
|
||||||
|
updateConfig,
|
||||||
|
sortApps,
|
||||||
|
sortCategories
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, actions)(OtherSettings);
|
@ -15,6 +15,8 @@ import {
|
|||||||
PinCategoryAction,
|
PinCategoryAction,
|
||||||
DeleteCategoryAction,
|
DeleteCategoryAction,
|
||||||
UpdateCategoryAction,
|
UpdateCategoryAction,
|
||||||
|
SortCategoriesAction,
|
||||||
|
ReorderCategoriesAction,
|
||||||
// Bookmarks
|
// Bookmarks
|
||||||
AddBookmarkAction,
|
AddBookmarkAction,
|
||||||
DeleteBookmarkAction,
|
DeleteBookmarkAction,
|
||||||
@ -49,6 +51,8 @@ export enum ActionTypes {
|
|||||||
pinCategory = 'PIN_CATEGORY',
|
pinCategory = 'PIN_CATEGORY',
|
||||||
deleteCategory = 'DELETE_CATEGORY',
|
deleteCategory = 'DELETE_CATEGORY',
|
||||||
updateCategory = 'UPDATE_CATEGORY',
|
updateCategory = 'UPDATE_CATEGORY',
|
||||||
|
sortCategories = 'SORT_CATEGORIES',
|
||||||
|
reorderCategories = 'REORDER_CATEGORIES',
|
||||||
// Bookmarks
|
// Bookmarks
|
||||||
addBookmark = 'ADD_BOOKMARK',
|
addBookmark = 'ADD_BOOKMARK',
|
||||||
deleteBookmark = 'DELETE_BOOKMARK',
|
deleteBookmark = 'DELETE_BOOKMARK',
|
||||||
@ -78,6 +82,8 @@ export type Action =
|
|||||||
PinCategoryAction |
|
PinCategoryAction |
|
||||||
DeleteCategoryAction |
|
DeleteCategoryAction |
|
||||||
UpdateCategoryAction |
|
UpdateCategoryAction |
|
||||||
|
SortCategoriesAction |
|
||||||
|
ReorderCategoriesAction |
|
||||||
// Bookmarks
|
// Bookmarks
|
||||||
AddBookmarkAction |
|
AddBookmarkAction |
|
||||||
DeleteBookmarkAction |
|
DeleteBookmarkAction |
|
||||||
|
@ -174,7 +174,7 @@ export const reorderApps = (apps: App[]) => async (dispatch: Dispatch) => {
|
|||||||
|
|
||||||
export interface SortAppsAction {
|
export interface SortAppsAction {
|
||||||
type: ActionTypes.sortApps;
|
type: ActionTypes.sortApps;
|
||||||
payload: {};
|
payload: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sortApps = () => async (dispatch: Dispatch) => {
|
export const sortApps = () => async (dispatch: Dispatch) => {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import axios from 'axios';
|
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, Config } from '../../interfaces';
|
||||||
import { CreateNotificationAction } from './notification';
|
import { CreateNotificationAction } from './notification';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +54,8 @@ export const addCategory = (formData: NewCategory) => async (dispatch: Dispatch)
|
|||||||
type: ActionTypes.addCategory,
|
type: ActionTypes.addCategory,
|
||||||
payload: res.data.data
|
payload: res.data.data
|
||||||
})
|
})
|
||||||
|
|
||||||
|
dispatch<any>(sortCategories());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
@ -173,6 +175,8 @@ export const updateCategory = (id: number, formData: NewCategory) => async (disp
|
|||||||
type: ActionTypes.updateCategory,
|
type: ActionTypes.updateCategory,
|
||||||
payload: res.data.data
|
payload: res.data.data
|
||||||
})
|
})
|
||||||
|
|
||||||
|
dispatch<any>(sortCategories());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
@ -261,4 +265,60 @@ export const updateBookmark = (bookmarkId: number, formData: NewBookmark, previo
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SORT CATEGORIES
|
||||||
|
*/
|
||||||
|
export interface SortCategoriesAction {
|
||||||
|
type: ActionTypes.sortCategories;
|
||||||
|
payload: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sortCategories = () => async (dispatch: Dispatch) => {
|
||||||
|
try {
|
||||||
|
const res = await axios.get<ApiResponse<Config>>('/api/config/useOrdering');
|
||||||
|
|
||||||
|
dispatch<SortCategoriesAction>({
|
||||||
|
type: ActionTypes.sortCategories,
|
||||||
|
payload: res.data.data.value
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REORDER CATEGORIES
|
||||||
|
*/
|
||||||
|
export interface ReorderCategoriesAction {
|
||||||
|
type: ActionTypes.reorderCategories;
|
||||||
|
payload: Category[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ReorderQuery {
|
||||||
|
categories: {
|
||||||
|
id: number;
|
||||||
|
orderId: number;
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const reorderCategories = (categories: Category[]) => async (dispatch: Dispatch) => {
|
||||||
|
try {
|
||||||
|
const updateQuery: ReorderQuery = { categories: [] }
|
||||||
|
|
||||||
|
categories.forEach((category, index) => updateQuery.categories.push({
|
||||||
|
id: category.id,
|
||||||
|
orderId: index + 1
|
||||||
|
}))
|
||||||
|
|
||||||
|
await axios.put<ApiResponse<{}>>('/api/categories/0/reorder', updateQuery);
|
||||||
|
|
||||||
|
dispatch<ReorderCategoriesAction>({
|
||||||
|
type: ActionTypes.reorderCategories,
|
||||||
|
payload: categories
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { ActionTypes, Action } from '../actions';
|
import { ActionTypes, Action } from '../actions';
|
||||||
import { Category, Bookmark } from '../../interfaces';
|
import { Category, Bookmark } from '../../interfaces';
|
||||||
|
import { sortData } from '../../utility';
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@ -141,6 +142,22 @@ const updateBookmark = (state: State, action: Action): State => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sortCategories = (state: State, action: Action): State => {
|
||||||
|
const sortedCategories = sortData<Category>(state.categories, action.payload);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
categories: sortedCategories
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const reorderCategories = (state: State, action: Action): State => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
categories: action.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -152,6 +169,8 @@ const bookmarkReducer = (state = initialState, action: Action) => {
|
|||||||
case ActionTypes.updateCategory: return updateCategory(state, action);
|
case ActionTypes.updateCategory: return updateCategory(state, action);
|
||||||
case ActionTypes.deleteBookmark: return deleteBookmark(state, action);
|
case ActionTypes.deleteBookmark: return deleteBookmark(state, action);
|
||||||
case ActionTypes.updateBookmark: return updateBookmark(state, action);
|
case ActionTypes.updateBookmark: return updateBookmark(state, action);
|
||||||
|
case ActionTypes.sortCategories: return sortCategories(state, action);
|
||||||
|
case ActionTypes.reorderCategories: return reorderCategories(state, action);
|
||||||
default: return state;
|
default: return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,14 +37,32 @@ exports.createCategory = asyncWrapper(async (req, res, next) => {
|
|||||||
// @route GET /api/categories
|
// @route GET /api/categories
|
||||||
// @access Public
|
// @access Public
|
||||||
exports.getCategories = asyncWrapper(async (req, res, next) => {
|
exports.getCategories = asyncWrapper(async (req, res, next) => {
|
||||||
const categories = await Category.findAll({
|
// Get config from database
|
||||||
include: [{
|
const useOrdering = await Config.findOne({
|
||||||
model: Bookmark,
|
where: { key: 'useOrdering' }
|
||||||
as: 'bookmarks'
|
|
||||||
}],
|
|
||||||
order: [[ Sequelize.fn('lower', Sequelize.col('Category.name')), 'ASC' ]]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const orderType = useOrdering ? useOrdering.value : 'createdAt';
|
||||||
|
let categories;
|
||||||
|
|
||||||
|
if (orderType == 'name') {
|
||||||
|
categories = await Category.findAll({
|
||||||
|
include: [{
|
||||||
|
model: Bookmark,
|
||||||
|
as: 'bookmarks'
|
||||||
|
}],
|
||||||
|
order: [[ Sequelize.fn('lower', Sequelize.col('Category.name')), 'ASC' ]]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
categories = await Category.findAll({
|
||||||
|
include: [{
|
||||||
|
model: Bookmark,
|
||||||
|
as: 'bookmarks'
|
||||||
|
}],
|
||||||
|
order: [[ orderType, 'ASC' ]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
data: categories
|
data: categories
|
||||||
@ -119,6 +137,22 @@ exports.deleteCategory = asyncWrapper(async (req, res, next) => {
|
|||||||
where: { id: req.params.id }
|
where: { id: req.params.id }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: {}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// @desc Reorder categories
|
||||||
|
// @route PUT /api/categories/0/reorder
|
||||||
|
// @access Public
|
||||||
|
exports.reorderCategories = asyncWrapper(async (req, res, next) => {
|
||||||
|
req.body.categories.forEach(async ({ id, orderId }) => {
|
||||||
|
await Category.update({ orderId }, {
|
||||||
|
where: { id }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
data: {}
|
data: {}
|
||||||
|
@ -6,7 +6,8 @@ const {
|
|||||||
getCategories,
|
getCategories,
|
||||||
getCategory,
|
getCategory,
|
||||||
updateCategory,
|
updateCategory,
|
||||||
deleteCategory
|
deleteCategory,
|
||||||
|
reorderCategories
|
||||||
} = require('../controllers/category');
|
} = require('../controllers/category');
|
||||||
|
|
||||||
router
|
router
|
||||||
@ -20,4 +21,8 @@ router
|
|||||||
.put(updateCategory)
|
.put(updateCategory)
|
||||||
.delete(deleteCategory);
|
.delete(deleteCategory);
|
||||||
|
|
||||||
|
router
|
||||||
|
.route('/0/reorder')
|
||||||
|
.put(reorderCategories);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
Loading…
Reference in New Issue
Block a user