diff --git a/client/src/components/admin_v2/Common/FeaturedMedia.jsx b/client/src/components/admin_v2/Common/FeaturedMedia.jsx
index 53c7ef3d..de47b76f 100644
--- a/client/src/components/admin_v2/Common/FeaturedMedia.jsx
+++ b/client/src/components/admin_v2/Common/FeaturedMedia.jsx
@@ -4,13 +4,12 @@ import React, { useEffect, useState } from 'react';
// libraries
import { Card, Typography } from '@mui/material';
-// media imports
-import SharedMedia, { thumb, thumbInner } from './sharedMedia';
-import imagekit from '../../../utils/imagekit';
-
// graphql
import { GraphClient } from '../../../config/ApolloClient';
import addMedia from '../../../graphql/mutations/media/addMedia';
+import imagekit from '../../../utils/imageKit';
+// media imports
+import SharedMedia, { thumb, thumbInner } from './sharedMedia';
export default function FeaturedMedia({
height,
diff --git a/client/src/components/admin_v2/Common/Tags.jsx b/client/src/components/admin_v2/Common/Tags.jsx
index 97504a02..81d49531 100644
--- a/client/src/components/admin_v2/Common/Tags.jsx
+++ b/client/src/components/admin_v2/Common/Tags.jsx
@@ -1,14 +1,20 @@
-import { Cancel } from '@mui/icons-material';
+import { useEffect, useRef, useState } from 'react';
+
+import { Cancel, Sell } from '@mui/icons-material';
import { Stack, TextField, Typography } from '@mui/material';
+import { makeStyles } from '@mui/styles';
import { Box } from '@mui/system';
-import { useEffect } from 'react';
-import { useRef, useState } from 'react';
+
+import { GraphClient } from '../../../config/ApolloClient';
+import updateArticleTags from '../../../graphql/mutations/article/updateArticleTags';
+import createTag from '../../../graphql/mutations/tag/createTag';
+import useTagAutoComplete from '../../../hooks/useTagAutoComplete';
const Tags = ({ data, handleDelete }) => {
return (
{
- {data}
+ {data.name}
{
);
};
-export default function ArticleTags({ tag, underlineVisible = false }) {
- const [tags, SetTags] = useState([]);
+export default function ArticleTags({
+ tag,
+ adminTags,
+ isAdmin,
+ id,
+ setErrorMessageAndError,
+}) {
+ const [tags, setTags] = useState([]);
+ const [active, setActive] = useState(false);
+ const [search, setSearch] = useState('');
const tagRef = useRef();
+ const classes = useStyles({ active });
+
+ const autoCompleteData = useTagAutoComplete(search, isAdmin, 5);
useEffect(() => {
- console.log(tag);
- if (tag) {
- const tagData = tag.map((data) => data.name);
- SetTags(tagData);
+ if (adminTags) {
+ const adminTagData = adminTags.map((data) => ({
+ ...data,
+ isAdmin: true,
+ }));
+ setTags([...adminTagData, ...tag]);
}
- }, [tag]);
+ }, []);
- const handleDelete = (value) => {
- const newtags = tags.filter((val) => val !== value);
- SetTags(newtags);
+ const handleDelete = async (value) => {
+ await updateTag(value.reference, false);
};
- const handleOnSubmit = (e) => {
- e.preventDefault();
- if (tagRef.current.value === '') return;
+ const handleCreate = async () => {
+ const {
+ data: { createTag: createdTag },
+ } = await GraphClient.mutate({
+ mutation: createTag,
+ variables: {
+ name: tagRef.current.value,
+ isAdmin: isAdmin,
+ },
+ });
+
+ await updateTag(createdTag.id, true);
+ };
+
+ const updateTag = async (tagId, isAdded) => {
+ if (tags.some((tag) => tag.reference === tagId && isAdded)) {
+ setErrorMessageAndError
+ ? setErrorMessageAndError('Tag already exists')
+ : null;
+ tagRef.current.value = '';
+ setActive(false);
+ return false;
+ }
+
+ const {
+ data: { updateArticleTags: updatedTags },
+ } = await GraphClient.mutate({
+ mutation: updateArticleTags,
+ variables: {
+ id: id,
+ tag: tagId,
+ isAdded: isAdded,
+ isAdmin: isAdmin,
+ },
+ });
- SetTags([...tags, tagRef.current.value]);
+ const updatedAdminTags = isAdmin
+ ? updatedTags.adminTags.map((data) => ({
+ ...data,
+ isAdmin: true,
+ }))
+ : [];
+ const updatedTag = isAdmin ? [] : updatedTags.tags;
+ setTags([...updatedAdminTags, ...updatedTag]);
tagRef.current.value = '';
+ setActive(false);
};
+
+ const searchQuery = (e) => {
+ e.preventDefault();
+ setSearch(e.target.value);
+ };
+
+ const searchActive = () => {
+ setActive((current) => !current);
+ };
+
return (
-
- ),
- disableUnderline: underlineVisible,
- }}
- />
-
+
+
+ {tags.map((data, index) => {
+ return ;
+ })}
+
+
+
+
+ {tagRef.current?.value?.length ? (
+
+ {autoCompleteData?.map(({ id, name }) => (
+
updateTag(id, true)}
+ >
+ {name}
+
+ ))}
+
+ Create Tag: {tagRef.current.value}
+
+
+ ) : (
+ <>>
+ )}
+
+
);
}
+
+const useStyles = makeStyles({
+ search: {
+ width: (_) => (_.active ? 150 : 0),
+ opacity: (_) => (_.active ? 1 : 0),
+ transition: '1s',
+ top: '0px',
+ position: 'relative',
+ },
+ tagForm: {
+ display: 'flex',
+ alignItems: 'center',
+ gap: 10,
+ },
+ tagSuggestions: {
+ position: 'absolute',
+ background: '#FEFEFF',
+ width: '100%',
+ padding: '10px',
+ zIndex: '20022',
+ borderRadius: '0px 0px 5px 5px',
+ border: '1px #ECEDEC',
+ borderStyle: 'none solid solid',
+ boxShadow: '0px 0px 5px grey',
+ display: (_) => (_.active ? 'block' : 'none'),
+ },
+ tagList: {
+ position: 'absoulte',
+ display: 'flex',
+ alignItems: 'center',
+ cursor: 'pointer',
+ fontSize: '14px',
+ },
+});
diff --git a/client/src/graphql/mutations/article/updateArticleTags.js b/client/src/graphql/mutations/article/updateArticleTags.js
new file mode 100644
index 00000000..5cde1634
--- /dev/null
+++ b/client/src/graphql/mutations/article/updateArticleTags.js
@@ -0,0 +1,24 @@
+import { gql } from '@apollo/client';
+
+const updateArticleTags = gql`
+ mutation ($id: ID!, $tag: ID!, $isAdded: Boolean!, $isAdmin: Boolean!) {
+ updateArticleTags(
+ id: $id
+ tag: $tag
+ isAdded: $isAdded
+ isAdmin: $isAdmin
+ ) {
+ tags {
+ name
+ reference
+ isAdmin
+ }
+ adminTags {
+ name
+ reference
+ }
+ }
+ }
+`;
+
+export default updateArticleTags;
diff --git a/client/src/graphql/mutations/tag/createTag.js b/client/src/graphql/mutations/tag/createTag.js
new file mode 100644
index 00000000..59ec1171
--- /dev/null
+++ b/client/src/graphql/mutations/tag/createTag.js
@@ -0,0 +1,13 @@
+import { gql } from '@apollo/client';
+
+const createTag = gql`
+ mutation createTag($name: String!, $isAdmin: Boolean, $adminColor: String) {
+ createTag(name: $name, isAdmin: $isAdmin, adminColor: $adminColor) {
+ id
+ name
+ isAdmin
+ }
+ }
+`;
+
+export default createTag;
diff --git a/client/src/graphql/queries/article/listAllArticles.js b/client/src/graphql/queries/article/listAllArticles.js
index c1e8f089..3065cfef 100644
--- a/client/src/graphql/queries/article/listAllArticles.js
+++ b/client/src/graphql/queries/article/listAllArticles.js
@@ -15,6 +15,11 @@ const listAllArticles = gql`
categories {
number
}
+ tags {
+ name
+ reference
+ isAdmin
+ }
adminTags {
name
reference
diff --git a/client/src/graphql/queries/tag/getTagAutocomplete.js b/client/src/graphql/queries/tag/getTagAutocomplete.js
new file mode 100644
index 00000000..c721b3e9
--- /dev/null
+++ b/client/src/graphql/queries/tag/getTagAutocomplete.js
@@ -0,0 +1,16 @@
+import { gql } from '@apollo/client';
+
+const getAutocomplete = gql`
+ query ($searchTerm: String!, $isAdmin: Boolean!, $limit: Int) {
+ getTagAutocomplete(
+ searchTerm: $searchTerm
+ isAdmin: $isAdmin
+ limit: $limit
+ ) {
+ id
+ name
+ isAdmin
+ }
+ }
+`;
+export default getAutocomplete;
diff --git a/client/src/hooks/useTagAutoComplete.js b/client/src/hooks/useTagAutoComplete.js
new file mode 100644
index 00000000..c74b012a
--- /dev/null
+++ b/client/src/hooks/useTagAutoComplete.js
@@ -0,0 +1,40 @@
+import { useEffect, useState } from 'react';
+
+import { GraphClient } from '../config/ApolloClient';
+import getTagAutocomplete from '../graphql/queries/tag/getTagAutocomplete';
+
+const useTagAutoComplete = (searchTag, isAdmin, limit) => {
+ const [searchKeyword, setSearchKeyword] = useState(searchTag);
+ const [result, setResult] = useState([]);
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setSearchKeyword(searchTag);
+ }, 100);
+
+ return () => clearTimeout(timer);
+ }, [searchTag]);
+
+ useEffect(() => {
+ if (!searchKeyword) return;
+
+ (async () => {
+ const {
+ data: { getTagAutocomplete: autoCompleteResult },
+ } = await GraphClient.query({
+ query: getTagAutocomplete,
+ variables: {
+ searchTerm: searchKeyword,
+ isAdmin: isAdmin,
+ limit: limit,
+ },
+ });
+
+ setResult(autoCompleteResult);
+ })();
+ }, [searchKeyword]);
+
+ return result;
+};
+
+export default useTagAutoComplete;
diff --git a/client/src/pages/admin_v2/browse.jsx b/client/src/pages/admin_v2/browse.jsx
index 1dab0d4a..6bbe8295 100644
--- a/client/src/pages/admin_v2/browse.jsx
+++ b/client/src/pages/admin_v2/browse.jsx
@@ -1,21 +1,17 @@
+import Head from 'next/head';
import { useRouter } from 'next/router';
+import { parseCookies } from 'nookies';
import ActivityIndicator from '../../components/shared/ActivityIndicator';
-import BrowseArticle from '../../screens/admin_v2/Browse';
-import Custom500 from '../500';
-
-import { parseCookies } from 'nookies';
import { getApolloLink, GraphClient } from '../../config/ApolloClient';
-import listAllArticle from '../../graphql/queries/article/listAllArticles';
import countTotalArticles from '../../graphql/queries/article/countTotalArticles';
-import Head from 'next/head';
+import listAllArticle from '../../graphql/queries/article/listAllArticles';
+import BrowseArticle from '../../screens/admin_v2/Browse';
+import Custom500 from '../500';
-const browseArticlePage = ({ articles, totalArticles, isError, error }) => {
+const BrowseArticlePage = ({ articles, totalArticles, isError, error }) => {
const { isFallback } = useRouter();
- console.log(articles, totalArticles);
if (isError) return ;
- console.log(isFallback);
- console.log(!isFallback && articles && totalArticles);
return (
<>
@@ -32,7 +28,7 @@ const browseArticlePage = ({ articles, totalArticles, isError, error }) => {
);
};
-export default browseArticlePage;
+export default BrowseArticlePage;
export async function getServerSideProps(context) {
try {
diff --git a/client/src/pages/admin_v2/index.jsx b/client/src/pages/admin_v2/index.jsx
index 75b850fd..6c6c1831 100644
--- a/client/src/pages/admin_v2/index.jsx
+++ b/client/src/pages/admin_v2/index.jsx
@@ -1,9 +1,8 @@
import React from 'react';
import Paperbase from '../../components/admin_v2/Marginals/Marginals';
-import Custom500 from '../500.jsx';
-
import getAccess from '../../utils/getAccess';
+import Custom500 from '../500.jsx';
const Admin = ({ isError }) => {
if (isError) {
diff --git a/client/src/screens/admin_v2/Browse.jsx b/client/src/screens/admin_v2/Browse.jsx
index 5a474c0b..c98cee8f 100644
--- a/client/src/screens/admin_v2/Browse.jsx
+++ b/client/src/screens/admin_v2/Browse.jsx
@@ -1,28 +1,29 @@
-import React, { useState, useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
+
import Link from 'next/link';
+import Box from '@mui/material/Box';
+import Paper from '@mui/material/Paper';
// Material UI
import { styled } from '@mui/material/styles';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell, { tableCellClasses } from '@mui/material/TableCell';
-import TablePagination from '@mui/material/TablePagination';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
+import TablePagination from '@mui/material/TablePagination';
import TableRow from '@mui/material/TableRow';
-import Paper from '@mui/material/Paper';
-import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
+
import ArticleStatusMenu from '../../components/admin_v2/Browse/ArticleStatusMenu';
import DialogBox from '../../components/admin_v2/Browse/DialogBox';
+import SnackBarAleart from '../../components/admin_v2/Common/SnackBarAleart';
import ArticleTags from '../../components/admin_v2/Common/Tags';
-
-import determineCategory from '../../utils/determineCategory';
import Marginals from '../../components/admin_v2/Marginals/Marginals';
import { GraphClient } from '../../config/ApolloClient';
-import listAllArticles from '../../graphql/queries/article/listAllArticles';
import updateArticlePublishStatus from '../../graphql/mutations/article/updateArticlePublishStatus';
-import SnackBarAleart from '../../components/admin_v2/Common/SnackBarAleart';
+import listAllArticles from '../../graphql/queries/article/listAllArticles';
+import determineCategory from '../../utils/determineCategory';
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
@@ -46,6 +47,7 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
const BrowseArticle = ({ articles, totalArticles }) => {
const [_articles, setArticles] = useState(articles);
+ const [rowsPerPage, setRowsPerPage] = React.useState(25);
const [row, setRow] = useState([]);
const [page, setPage] = useState(0);
@@ -70,6 +72,10 @@ const BrowseArticle = ({ articles, totalArticles }) => {
setPage(newPage);
};
+ const handleChangeRowsPerPage = (_event) => {
+ setRowsPerPage(+_event.target.value);
+ };
+
//snack bar aleart
const [error, setError] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
@@ -107,6 +113,7 @@ const BrowseArticle = ({ articles, totalArticles }) => {
publishStatus,
createdAt,
adminTags,
+ tags,
}) => {
const authorNames = authors?.map((author) => author.name).join(', ');
const categoryNames = categories
@@ -124,6 +131,7 @@ const BrowseArticle = ({ articles, totalArticles }) => {
categoryNames,
publishStatus,
adminTags,
+ tags,
createdAt: new Date(createdAt).toString().substring(4, 21),
};
},
@@ -137,11 +145,15 @@ const BrowseArticle = ({ articles, totalArticles }) => {
data: { listAllArticles: articles },
} = await GraphClient.query({
query: listAllArticles,
- variables: { limit: 25, offset: 25 * page, onlyPublished: false },
+ variables: {
+ limit: rowsPerPage,
+ offset: rowsPerPage * page,
+ onlyPublished: false,
+ },
});
setArticles(articles);
})();
- }, [page]);
+ }, [rowsPerPage, page]);
return (
@@ -206,7 +218,12 @@ const BrowseArticle = ({ articles, totalArticles }) => {
'&:hover': { display: 'initial' },
}}
>
-
+
@@ -234,12 +251,12 @@ const BrowseArticle = ({ articles, totalArticles }) => {
diff --git a/client/src/screens/admin_v2/Edit.jsx b/client/src/screens/admin_v2/Edit.jsx
index d801bea4..fd0afc21 100644
--- a/client/src/screens/admin_v2/Edit.jsx
+++ b/client/src/screens/admin_v2/Edit.jsx
@@ -1,35 +1,33 @@
import React, { useState } from 'react';
-//graphql
-import { GraphClient } from '../../config/ApolloClient';
-import updateArticleProps from '../../graphql/mutations/article/updateArticleProps';
-import updateArticleUsers from '../../graphql/mutations/article/updateArticleUsers';
-import updateArticleCategories from '../../graphql/mutations/article/updateArticleCategories';
-import updateArticleRestriction from '../../graphql/mutations/article/updateArticleRestriction';
-import updateArticleApprovalStatus from '../../graphql/mutations/article/updateArticleApprovalStatus';
-
-//material ui
-import Paper from '@mui/material/Paper';
-import InputBase from '@mui/material/InputBase';
-import Box from '@mui/material/Box';
import SendIcon from '@mui/icons-material/Send';
+import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
-import Radio from '@mui/material/Radio';
-import RadioGroup from '@mui/material/RadioGroup';
-import FormControlLabel from '@mui/material/FormControlLabel';
+import Container from '@mui/material/Container';
import FormControl from '@mui/material/FormControl';
+import FormControlLabel from '@mui/material/FormControlLabel';
import FormLabel from '@mui/material/FormLabel';
-import Container from '@mui/material/Container';
+import InputBase from '@mui/material/InputBase';
+//material ui
+import Paper from '@mui/material/Paper';
+import Radio from '@mui/material/Radio';
+import RadioGroup from '@mui/material/RadioGroup';
import useMediaQuery from '@mui/material/useMediaQuery';
-//components
-import SnackBarAleart from '../../components/admin_v2/Common/SnackBarAleart';
import AuthorsCard from '../../components/admin_v2/AddNew/AuthorCards';
import CategoryCard from '../../components/admin_v2/AddNew/CategoryCard';
-import Marginals from '../../components/admin_v2/Marginals/Marginals';
import FeaturedMedia from '../../components/admin_v2/Common/FeaturedMedia';
+//components
+import SnackBarAleart from '../../components/admin_v2/Common/SnackBarAleart';
import ArticleTags from '../../components/admin_v2/Common/Tags';
-
+import Marginals from '../../components/admin_v2/Marginals/Marginals';
+//graphql
+import { GraphClient } from '../../config/ApolloClient';
+import updateArticleApprovalStatus from '../../graphql/mutations/article/updateArticleApprovalStatus';
+import updateArticleCategories from '../../graphql/mutations/article/updateArticleCategories';
+import updateArticleProps from '../../graphql/mutations/article/updateArticleProps';
+import updateArticleRestriction from '../../graphql/mutations/article/updateArticleRestriction';
+import updateArticleUsers from '../../graphql/mutations/article/updateArticleUsers';
//utils
import explorer from '../../utils/categoryCard';
import STORES from '../../utils/getStores';
@@ -282,7 +280,13 @@ const EditArticle = ({ allUsers, article }) => {
-
+