refactor & redesign
This commit is contained in:
parent
e565f450b8
commit
d9f9c8c013
23
src/App.tsx
23
src/App.tsx
|
|
@ -9,6 +9,8 @@ import "./assets/styles/style.scss";
|
|||
|
||||
// Types
|
||||
import { PostType } from "./types/posts";
|
||||
import { SourceType } from "./types/sources";
|
||||
import { LinksAll } from "./types/links";
|
||||
|
||||
// Pages
|
||||
import Login from "./pages/Login";
|
||||
|
|
@ -18,6 +20,10 @@ import Posts from "./pages/Posts";
|
|||
import Details from "./pages/Details";
|
||||
import Post from "./pages/Post";
|
||||
import Source from "./pages/Source";
|
||||
import EditSource from "./pages/EditSource";
|
||||
|
||||
// Helpers
|
||||
import { getLinks } from "./helpers/apiRequests";
|
||||
|
||||
const App = () => {
|
||||
const navigate = useNavigate();
|
||||
|
|
@ -35,6 +41,8 @@ const App = () => {
|
|||
},
|
||||
]);
|
||||
|
||||
const [sources, setSources] = useState<SourceType[]>();
|
||||
|
||||
const [user, setUser] = useState({
|
||||
username: "",
|
||||
accessLevel: "",
|
||||
|
|
@ -49,6 +57,10 @@ const App = () => {
|
|||
|
||||
const userValue = useMemo(() => ({ user, setUser }), [user, setUser]);
|
||||
const postValue = useMemo(() => ({ posts, setPosts }), [posts, setPosts]);
|
||||
const sourceValue = useMemo(
|
||||
() => ({ sources, setSources }),
|
||||
[sources, setSources]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!user.username) {
|
||||
|
|
@ -59,8 +71,12 @@ const App = () => {
|
|||
}
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
getLinks(setSources);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PostContext.Provider value={postValue}>
|
||||
<PostContext.Provider value={{ postValue, sourceValue }}>
|
||||
<UserContext.Provider value={userValue}>
|
||||
<div className="App">
|
||||
<Routes>
|
||||
|
|
@ -68,7 +84,12 @@ const App = () => {
|
|||
<Route path="/dashboard" element={<Main child={<Dashboard />} />} />
|
||||
<Route path="/posts" element={<Main child={<Posts />} />} />
|
||||
<Route path="/source" element={<Main child={<Source />} />} />
|
||||
<Route
|
||||
path="/source/edit/:id"
|
||||
element={<Main child={<EditSource />} />}
|
||||
/>
|
||||
<Route path="/posts/:id" element={<Main child={<Post />} />} />
|
||||
|
||||
<Route
|
||||
path="/user_details"
|
||||
element={<Main child={<Details />} />}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 1rem;
|
||||
gap: 2rem;
|
||||
width: 100%;
|
||||
padding: 0.8rem 0.4rem 0.8rem 1.2rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
.source-edit {
|
||||
&.inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rem;
|
||||
}
|
||||
|
||||
&__content {
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__info,
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3rem;
|
||||
padding: 1rem;
|
||||
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__input {
|
||||
color: $base-gray;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.8rem;
|
||||
font-size: 1.6rem;
|
||||
|
||||
input {
|
||||
font-size: 1.6rem;
|
||||
background: $light-black;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__submit {
|
||||
font-size: 1.6rem;
|
||||
cursor: pointer;
|
||||
color: $base-gray;
|
||||
border-radius: 0.5rem;
|
||||
background: $base-blue;
|
||||
@include transition-std;
|
||||
padding: 1.6rem 1.2rem;
|
||||
|
||||
&:hover {
|
||||
@include transition-std;
|
||||
background: $hover-blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -73,7 +73,7 @@
|
|||
input {
|
||||
font-size: 1.6rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 0.2rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
&--check {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@
|
|||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: 1.6rem;
|
||||
@include transition-std;
|
||||
|
||||
&:hover {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
padding: 1rem 2rem;
|
||||
border-radius: 0.5rem;
|
||||
background: $base-blue;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
@include transition-std;
|
||||
|
|
@ -46,6 +45,7 @@
|
|||
padding: 1rem 1.2rem;
|
||||
border-radius: 0.2rem;
|
||||
cursor: default;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
&__wrapper {
|
||||
|
|
@ -57,6 +57,7 @@
|
|||
padding: 1rem 1.2rem;
|
||||
color: $base-gray;
|
||||
background: $light-black;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
&.inner {
|
||||
|
|
@ -168,42 +169,37 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
max-width: 30rem;
|
||||
|
||||
border-radius: 0.2rem;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
padding: 0.6rem 1.2rem;
|
||||
color: #fff;
|
||||
padding: 1rem 1.2rem;
|
||||
color: $base-gray;
|
||||
font-size: 1.6rem;
|
||||
background-color: #7c69ef;
|
||||
border: 0.1rem solid #7c69ef;
|
||||
background-color: $base-blue;
|
||||
|
||||
@include transition-std;
|
||||
&:hover {
|
||||
@include transition-std;
|
||||
background-color: #705ed6;
|
||||
border: 0.1rem solid #705ed6;
|
||||
background-color: $hover-blue;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 1.6rem;
|
||||
padding: 1rem 1.2rem;
|
||||
border: 1px solid #b8b9bb;
|
||||
border-radius: 0.2rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 0.5rem;
|
||||
cursor: default;
|
||||
background: #ebedef;
|
||||
background: $light-black;
|
||||
}
|
||||
|
||||
textarea {
|
||||
background: #ebedef;
|
||||
background: $light-black;
|
||||
cursor: default;
|
||||
padding: 1rem 1.2rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
resize: none;
|
||||
outline: none;
|
||||
font-size: 1.6rem;
|
||||
|
||||
border: 1px solid #b8b9bb;
|
||||
border-radius: 0.2rem;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
&__block {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
&__head {
|
||||
svg {
|
||||
|
|
@ -95,10 +94,18 @@
|
|||
gap: 1rem;
|
||||
color: $base-gray;
|
||||
background: $base-black;
|
||||
|
||||
&:nth-child(2n) {
|
||||
background: $light-blue;
|
||||
td {
|
||||
color: $light-black;
|
||||
svg {
|
||||
fill: $base-black;
|
||||
}
|
||||
span {
|
||||
color: $base-black;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,8 +146,8 @@
|
|||
}
|
||||
|
||||
svg {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
span {
|
||||
|
|
|
|||
|
|
@ -8,3 +8,4 @@
|
|||
@import "./posts";
|
||||
@import "./details";
|
||||
@import "./source";
|
||||
@import "./edit-source";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { IconContext } from "react-icons";
|
|||
// Icons
|
||||
import { FaMeteor } from "react-icons/fa";
|
||||
import { GiHamburgerMenu } from "react-icons/gi";
|
||||
import { FaUserCog } from "react-icons/fa";
|
||||
import { FaUserAlt } from "react-icons/fa";
|
||||
|
||||
// Types
|
||||
import { userContextType } from "../types/user";
|
||||
|
|
@ -52,7 +52,7 @@ const Nav = ({ aside, setAside }: Props) => {
|
|||
}}
|
||||
>
|
||||
<IconContext.Provider value={{ color: "#8DD77F" }}>
|
||||
<FaUserCog className="nav__right__user__img" />
|
||||
<FaUserAlt className="nav__right__user__img" />
|
||||
</IconContext.Provider>
|
||||
|
||||
<span>Profile</span>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// Modules
|
||||
// Tyoes
|
||||
import { createContext } from "react";
|
||||
import { ContextType } from "../types/context";
|
||||
|
||||
export const PostContext: any = createContext(null);
|
||||
export const PostContext: any = createContext<ContextType | null>(null);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export const updateLink = (
|
|||
data: { name: string; source: string }
|
||||
) => {
|
||||
axios
|
||||
.put(`http://95.85.124.41:8080/link/update/${id}`, { source: data.source })
|
||||
.put(`http://95.85.124.41:8080/link/update/${id}`, data)
|
||||
.then((res) => {
|
||||
setSuccess(res.data.message);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
// Modules
|
||||
import React, { useState, useEffect, useContext } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { IconContext } from "react-icons/lib";
|
||||
import { PostContext } from "../context/PostContext";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
// Icons
|
||||
import { FaRegEdit } from "react-icons/fa";
|
||||
|
||||
// Types
|
||||
import { SourceType, SourceEditDataType } from "../types/sources";
|
||||
import { ContextType } from "../types/context";
|
||||
|
||||
// Helpers
|
||||
import { getLinks, updateLink } from "../helpers/apiRequests";
|
||||
|
||||
const EditSource = () => {
|
||||
const navigate = useNavigate();
|
||||
const { sources, setSources } =
|
||||
useContext<ContextType>(PostContext).sourceValue;
|
||||
const [source, setSource] = useState<SourceType>();
|
||||
useEffect(() => {
|
||||
if (sources) {
|
||||
sources.map((post: SourceType) => {
|
||||
if (post.id.toString() === id) {
|
||||
setSource(post);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [sources]);
|
||||
|
||||
const { id } = useParams();
|
||||
const [data, setData] = useState<SourceEditDataType>({
|
||||
name: "",
|
||||
source: "",
|
||||
});
|
||||
|
||||
return (
|
||||
<main className="source-edit">
|
||||
<div className="container">
|
||||
<div className="source-edit inner">
|
||||
<div className="dashboard__head source-edit__head">
|
||||
<IconContext.Provider value={{ color: "#8DD77F" }}>
|
||||
<FaRegEdit className="dashboard__img" />
|
||||
</IconContext.Provider>
|
||||
<h1>Edit source</h1>
|
||||
</div>
|
||||
<div className="source-edit__content">
|
||||
<form
|
||||
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
<div className="source-edit__info">
|
||||
<h2>Information</h2>
|
||||
<div className="source-edit__input">
|
||||
<label htmlFor="id">Source ID</label>
|
||||
<input
|
||||
readOnly
|
||||
type="text"
|
||||
id="id"
|
||||
value={source ? source.name : ""}
|
||||
/>
|
||||
</div>
|
||||
<div className="source-edit__input">
|
||||
<label htmlFor="name">Source old name</label>
|
||||
<input
|
||||
readOnly
|
||||
type="text"
|
||||
id="name"
|
||||
value={source ? source.name : ""}
|
||||
/>
|
||||
</div>
|
||||
<div className="source-edit__input">
|
||||
<label htmlFor="source">Source old link</label>
|
||||
<input
|
||||
readOnly
|
||||
type="text"
|
||||
id="source"
|
||||
value={source ? source.source : ""}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="source-edit__content">
|
||||
<h2>Edit</h2>
|
||||
<div className="source-edit__input">
|
||||
<label htmlFor="new_name">Source new name</label>
|
||||
<input
|
||||
placeholder="Enter new name"
|
||||
type="text"
|
||||
id="new_name"
|
||||
value={data.name}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setData({ ...data, name: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="source-edit__input">
|
||||
<label htmlFor="new_source">Source new link</label>
|
||||
<input
|
||||
placeholder="Enter new link"
|
||||
type="text"
|
||||
id="new_source"
|
||||
value={data.source}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setData({ ...data, source: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
className="source-edit__submit"
|
||||
onClick={() => {
|
||||
updateLink(() => {}, id ? parseInt(id) : 0, data);
|
||||
setTimeout(() => {
|
||||
navigate("/source");
|
||||
getLinks(setSources);
|
||||
}, 2000);
|
||||
}}
|
||||
>
|
||||
Update source
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditSource;
|
||||
|
|
@ -3,15 +3,19 @@ import { useContext, useState, useEffect } from "react";
|
|||
import { useParams } from "react-router-dom";
|
||||
import { PostContext } from "../context/PostContext";
|
||||
import { PostType } from "../types/posts";
|
||||
import { IconContext } from "react-icons";
|
||||
|
||||
// Icons
|
||||
import { ImNewspaper } from "react-icons/im";
|
||||
import { FaBoxOpen } from "react-icons/fa";
|
||||
import { BiLinkExternal } from "react-icons/bi";
|
||||
|
||||
// Helpers
|
||||
import { parseDate } from "../helpers/parseDate";
|
||||
import { capitalizeFirstLetter } from "../helpers/stringMethods";
|
||||
|
||||
// Types
|
||||
import { ContextType } from "../types/context";
|
||||
|
||||
const Post = () => {
|
||||
const date = new Date("0.0.0000");
|
||||
const [postData, setPostData] = useState<PostType>({
|
||||
|
|
@ -24,7 +28,7 @@ const Post = () => {
|
|||
createdAt: date,
|
||||
updatedAt: date,
|
||||
});
|
||||
const { posts } = useContext<any>(PostContext);
|
||||
const { posts } = useContext<ContextType>(PostContext).postValue;
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -41,7 +45,9 @@ const Post = () => {
|
|||
<div className="container">
|
||||
<div className="post inner">
|
||||
<div className="dashboard__head post__head">
|
||||
<ImNewspaper />
|
||||
<IconContext.Provider value={{ color: "#8DD77F" }}>
|
||||
<FaBoxOpen className="dashboard__img" />
|
||||
</IconContext.Provider>
|
||||
<h1 className="post__head">
|
||||
{postData.id !== -1 ? postData.title : ""}
|
||||
</h1>
|
||||
|
|
@ -97,7 +103,10 @@ const Post = () => {
|
|||
className="post__content__btn"
|
||||
href={postData.id !== -1 ? postData.link : ""}
|
||||
>
|
||||
<BiLinkExternal />
|
||||
<IconContext.Provider value={{ color: "#FFFFFF" }}>
|
||||
<BiLinkExternal />
|
||||
</IconContext.Provider>
|
||||
|
||||
<span>Link</span>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { parseDate } from "../helpers/parseDate";
|
|||
|
||||
// Types
|
||||
import { paramsType } from "../types/posts";
|
||||
|
||||
import { ContextType } from "../types/context";
|
||||
interface pageType {
|
||||
perPage: number;
|
||||
pageNumber: number;
|
||||
|
|
@ -24,7 +24,8 @@ interface pageType {
|
|||
|
||||
const Posts = () => {
|
||||
const [categories, setCategories] = useState<string[]>(["All"]);
|
||||
const { posts, setPosts } = useContext<any>(PostContext);
|
||||
const contextValue: ContextType = useContext<ContextType>(PostContext);
|
||||
const { posts, setPosts } = contextValue.postValue;
|
||||
const [category, setCategory] = useState<string>("All");
|
||||
const [sort, setSort] = useState<string>("id");
|
||||
const [page, setPage] = useState<pageType>({
|
||||
|
|
@ -309,7 +310,7 @@ const Posts = () => {
|
|||
</button>
|
||||
<input type="text" value={page.pageNumber} readOnly />
|
||||
<button
|
||||
disabled={posts[0] ? false : true}
|
||||
disabled={posts ? false : true}
|
||||
type="button"
|
||||
onClick={() =>
|
||||
setPage({ ...page, pageNumber: page.pageNumber + 1 })
|
||||
|
|
|
|||
|
|
@ -1,61 +1,34 @@
|
|||
// Modules
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, useContext } from "react";
|
||||
import { IconContext } from "react-icons";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
// Context
|
||||
import { PostContext } from "../context/PostContext";
|
||||
|
||||
// Icons
|
||||
import { FaSourcetree } from "react-icons/fa";
|
||||
import { FaRegEdit } from "react-icons/fa";
|
||||
import { FaTrash } from "react-icons/fa";
|
||||
import { getLinks } from "../helpers/apiRequests";
|
||||
|
||||
// Helpers
|
||||
import { deleteLink } from "../helpers/apiRequests";
|
||||
import { deleteLink, getLinks } from "../helpers/apiRequests";
|
||||
|
||||
// Types
|
||||
import { LinksAll } from "../types/links";
|
||||
// interface dataType {
|
||||
// createName: string;
|
||||
// createLink: string;
|
||||
// delete: number;
|
||||
// updateId: number;
|
||||
// updateName: string;
|
||||
// updateLink: string;
|
||||
// }
|
||||
// interface successType {
|
||||
// create: string;
|
||||
// delete: string;
|
||||
// update: string;
|
||||
// hasCreateUpdated: boolean;
|
||||
// hasDeleteUpdated: boolean;
|
||||
// hasUpdateUpdated: boolean;
|
||||
// }
|
||||
import { ContextType } from "../types/context";
|
||||
|
||||
const Source = () => {
|
||||
const defaultDate = new Date("00-00-00");
|
||||
|
||||
const { sources, setSources } =
|
||||
useContext<ContextType>(PostContext).sourceValue;
|
||||
const [deleted, setDeleted] = useState<boolean>(false);
|
||||
|
||||
const [all, setAll] = useState<LinksAll[]>([
|
||||
{
|
||||
id: -1,
|
||||
name: "",
|
||||
source: "",
|
||||
createdAt: defaultDate,
|
||||
updatedAt: defaultDate,
|
||||
},
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
getLinks(setAll);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (deleted) {
|
||||
setTimeout(() => {
|
||||
setDeleted(false);
|
||||
getLinks(setAll);
|
||||
getLinks(setSources);
|
||||
}, 2000);
|
||||
}
|
||||
}, [deleted, setDeleted]);
|
||||
|
|
@ -82,8 +55,8 @@ const Source = () => {
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{all[0].id !== -1 ? (
|
||||
all.map((source: LinksAll) => {
|
||||
{sources ? (
|
||||
sources.map((source: LinksAll) => {
|
||||
return (
|
||||
<tr key={uuidv4()}>
|
||||
<td>{source.id}</td>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// Modules
|
||||
import React, { SetStateAction } from "react";
|
||||
|
||||
// Types
|
||||
import { PostType } from "../types/posts";
|
||||
import { SourceType } from "../types/sources";
|
||||
|
||||
// Context type
|
||||
|
||||
export interface ContextType {
|
||||
postValue: {
|
||||
posts: PostType[];
|
||||
setPosts: React.Dispatch<SetStateAction<PostType[]>>;
|
||||
};
|
||||
sourceValue: {
|
||||
sources: SourceType[];
|
||||
setSources: React.Dispatch<SetStateAction<SourceType[]>>;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
export interface SourceType {
|
||||
id: number;
|
||||
name: string;
|
||||
source: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export interface SourceEditDataType {
|
||||
name: string;
|
||||
source: string;
|
||||
}
|
||||
Loading…
Reference in New Issue