-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Queries):Admin query management
- Loading branch information
YvetteNyibuka
committed
Jul 26, 2024
1 parent
09f1b6f
commit 00fa2e2
Showing
17 changed files
with
577 additions
and
56 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { DynamicData } from './DynamicData'; | ||
|
||
export interface QueryState { | ||
isLoading: boolean; | ||
singleQuery: DynamicData; | ||
error: string | null; | ||
querries: DynamicData; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { FC, useEffect, useState } from 'react'; | ||
import { CopyToClipboard } from 'react-copy-to-clipboard'; | ||
import { CopyType } from '../../@types/userType'; | ||
import { FaRegCopy } from 'react-icons/fa'; | ||
import { TiTick } from 'react-icons/ti'; | ||
|
||
const CopyButton: FC<CopyType> = ({ name, text, value }) => { | ||
const [copied, setCopied] = useState(false); | ||
|
||
useEffect(() => { | ||
const interval = setTimeout(() => { | ||
setCopied(false); | ||
}, 3000); | ||
|
||
return () => clearTimeout(interval); | ||
}, [copied]); | ||
|
||
return ( | ||
<CopyToClipboard | ||
text={value} | ||
onCopy={() => name === text && setCopied(true)} | ||
> | ||
<div className="flex ipad:gap-5 items-center pl-4 pr-1 py-1 border rounded justify-between "> | ||
<span className="text-[9px] ipad:text-xs"> | ||
{copied ? 'Copied' : name} | ||
</span> | ||
<button | ||
disabled={copied} | ||
className={`p-1 border rounded hover:bg-slate-200 ${copied && 'bg-action-success hover:bg-action-success'} transition-colors`} | ||
> | ||
{copied ? <TiTick size={24} fill="white" /> : <FaRegCopy size={24} />} | ||
</button> | ||
</div> | ||
</CopyToClipboard> | ||
); | ||
}; | ||
|
||
export default CopyButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { useNavigate } from 'react-router-dom'; | ||
import { ScaleLoader } from 'react-spinners'; | ||
import { DynamicData } from '../../@types/DynamicData'; | ||
import { getQuerries } from '../../redux/features/Queries/querySlice'; | ||
import { useAppDispatch, useAppSelector } from '../../redux/hooks/hooks'; | ||
import formatDate from '../../utils/DateConversion'; | ||
import Pagination from '../../utils/Pagination'; | ||
|
||
const Querries = () => { | ||
const dispatch = useAppDispatch(); | ||
const { isLoading, querries } = useAppSelector((state) => state.queries); | ||
const navigate = useNavigate(); | ||
|
||
const numberOfQuerries = querries.length; | ||
|
||
useEffect(() => { | ||
dispatch(getQuerries()).unwrap(); | ||
}, [dispatch]); | ||
|
||
const [currentPage, setCurrentPage] = useState(0); | ||
|
||
const itemsPerPage = 10; | ||
const orderArray = Array.isArray(querries) ? querries : []; | ||
const reversedOrderArray = [...orderArray].reverse(); | ||
const offset = currentPage * itemsPerPage; | ||
const query = reversedOrderArray.slice(offset, offset + itemsPerPage); | ||
const pageCount = Math.ceil(reversedOrderArray.length / itemsPerPage); | ||
|
||
const handlePageChange = (selectedPage: number) => { | ||
setCurrentPage(selectedPage); | ||
}; | ||
|
||
const handleSingleQuery = (id: string) => { | ||
navigate(`/dashboard/querries/${id}`); | ||
}; | ||
return ( | ||
<div className="parent_container relative max-h-[80%] overflow-y-scroll overflow-hidden pb-4 mt-4 h-full"> | ||
{isLoading ? ( | ||
<div className="w-full absolute h-full flex items-center justify-center"> | ||
<ScaleLoader | ||
color="#256490" | ||
role="progressbar" | ||
aria-label="single_product_loader" | ||
/> | ||
</div> | ||
) : numberOfQuerries <= 0 ? ( | ||
<div className="w-full h-[90%] flex items-center justify-center "> | ||
<h2 className="text-center font-bold text-2xl">No Messages</h2> | ||
</div> | ||
) : ( | ||
<> | ||
<div className="tableWrapper mt-1 text-[1rem] mx-5 laptop:mx-10 bg-neutral-white p-2 rounded-md max-w-[90%]"> | ||
<div className="flex justify-between items-center"> | ||
<h1 className="mb-5 text-lg">Messages</h1> | ||
</div> | ||
<table className="tables pt-2 p-3 overflow-hidden overflow-x-scroll max-w-[18rem] tablet:max-w-[100%]"> | ||
<thead className="bg-[#256490] text-neutral-white text-left overflow-hidden rounded-3xl p2"> | ||
<tr className="rounded-xl text-sm "> | ||
<th>No</th> | ||
<th>First Name</th> | ||
<th>Last Name</th> | ||
<th>Email</th> | ||
<th>Subject</th> | ||
<th>Message</th> | ||
<th className="expand">Date</th> | ||
</tr> | ||
</thead> | ||
<tbody className="text-slate-700"> | ||
{query.map((query: DynamicData, index: number) => ( | ||
<tr | ||
onClick={() => handleSingleQuery(query.id)} | ||
key={index} | ||
className={`hover:bg-primary-lightblue/30 cursor-pointer relative text-sm ${index % 2 !== 0 ? 'bg-[#DDDD]' : ''}`} | ||
> | ||
<td>{index + 1 + offset}</td> | ||
<td>{query.firstName}</td> | ||
<td>{query.lastName}</td> | ||
<td>{query.email}</td> | ||
<td>{query.subject}</td> | ||
<td> | ||
{query.message.length > 15 | ||
? query.message.slice(0, 25) + '...' | ||
: query.message} | ||
</td> | ||
<td>{formatDate(query.createdAt)}</td> | ||
</tr> | ||
))} | ||
</tbody> | ||
</table> | ||
</div> | ||
<div className="flex items-center justify-center"> | ||
<Pagination | ||
data-testid="pagination-component" | ||
pageCount={pageCount} | ||
currentPage={currentPage} | ||
onPageChange={handlePageChange} | ||
/> | ||
</div> | ||
</> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Querries; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { useEffect } from 'react'; | ||
import { useParams } from 'react-router-dom'; | ||
import { ScaleLoader } from 'react-spinners'; | ||
import { DynamicData } from '../../@types/DynamicData'; | ||
import BackButton from '../../components/buttons/BackButton'; | ||
import { getSingleQuery } from '../../redux/features/Queries/querySlice'; | ||
import { useAppDispatch, useAppSelector } from '../../redux/hooks/hooks'; | ||
import CopyButton from '../../components/buttons/CopyBtn'; | ||
|
||
const SingleQuerries = () => { | ||
const dispatch = useAppDispatch(); | ||
const { isLoading, singleQuery } = useAppSelector((state) => state.queries); | ||
const { id } = useParams<{ id: string }>(); | ||
const singleQueryNumber = singleQuery.length; | ||
useEffect(() => { | ||
if (id) { | ||
dispatch(getSingleQuery(id || '')).unwrap(); | ||
} | ||
}, [dispatch, id]); | ||
|
||
return ( | ||
<div className="parent_container relative max-h-[80%] overflow-y-scroll overflow-hidden pb-4 mt-4 h-full"> | ||
{isLoading ? ( | ||
<div className="w-full absolute h-full flex items-center justify-center"> | ||
<ScaleLoader | ||
color="#256490" | ||
role="progressbar" | ||
aria-label="single_product_loader" | ||
/> | ||
</div> | ||
) : singleQueryNumber <= 0 ? ( | ||
<div className="w-full h-[90%] flex items-center justify-center "> | ||
<h2 className="text-center font-bold text-2xl">No Messages</h2> | ||
</div> | ||
) : ( | ||
<> | ||
<div className="tableWrapper mt-1 text-[1rem] mx-5 laptop:mx-10 bg-neutral-white px-8 rounded-md max-w-[100%] py-7"> | ||
<div className="flex justify-end"> | ||
<BackButton | ||
isBordered | ||
url="/dashboard/querries" | ||
otherStyles="rounded-3xl p-2 bg-primary-lightblue/90 text-neutral-white hover:bg-primary-lightblue" | ||
title={''} | ||
/> | ||
</div> | ||
<div className="rounded-md"> | ||
{singleQuery.map((query: DynamicData, index: number) => ( | ||
<div key={index} className="space-y-4"> | ||
<h1 className="mb-5 text-2xl font-bold "> | ||
{query.firstName} {query.lastName} | ||
</h1> | ||
<div className="flex gap-3 ipad:items-center flex-col tablet:flex-row "> | ||
<h2 className="text-lg"> | ||
<span className="font-semibold pr-1">Email:</span> | ||
<span className="italic">{query.email}</span> | ||
</h2> | ||
<CopyButton | ||
name="Copy Email" | ||
text="Copy Email" | ||
value={query.email} | ||
/> | ||
</div> | ||
|
||
<p className="text-lg"> | ||
<span className="font-semibold pr-1">Message:</span> | ||
{query.message} | ||
</p> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
</> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default SingleQuerries; |
Oops, something went wrong.