jai #13

Merged
jaipandey merged 11 commits from jai into main 2025-07-31 06:59:43 +00:00
4 changed files with 106 additions and 100 deletions
Showing only changes of commit 7cbd74fc14 - Show all commits

View File

@ -83,11 +83,11 @@ const Contacts = () => {
const handleContactSubmit = async (data: ContactData, type: "") => {
try {
let res ;
let res;
setCreateAndInviteLoader(true);
if (type === 'Edit') {
res = await api.put(`/api/accounts/${activeAccountId}/contacts`, [data])
}else{
res = await api.put(`/api/accounts/${activeAccountId}/contacts`, [data])
} else {
res = await api.post(`/api/accounts/${activeAccountId}/contacts`, [data]);
}
if (res.status === 200) {
@ -115,82 +115,84 @@ const Contacts = () => {
return (
<>
<div className='flex justify-end my-2 cursor-pointer'>
<div
onClick={() => setShowModal((prev) => !prev)}
className="flex items-center gap-2 bg-[var(--primary)] px-3 py-1.5 rounded-sm hover:opacity-90 ">
<IoMdAdd className="text-white" />
<button
className="text-white rounded text-sm hover:opacity-90 cursor-pointer">
Add Contact
</button>
<div className='px-1.5'>
<div className='flex justify-end my-2 cursor-pointer'>
<div
onClick={() => setShowModal((prev) => !prev)}
className="flex items-center gap-2 bg-[var(--primary)] px-3 py-1.5 rounded-sm hover:opacity-90 ">
<IoMdAdd className="text-white" />
<button
className="text-white rounded text-sm hover:opacity-90 cursor-pointer">
Add Contact
</button>
</div>
</div>
</div>
<div className="overflow-y-auto max-h-[79vh] border border-gray-200 rounded shadow-sm no-scrollbar">
<table className="min-w-full text-sm bg-white">
<thead className="bg-gray-100 text-gray-700 uppercase text-xs tracking-wider sticky top-0 z-10">
<tr>
<th className="px-4 py-3 text-left">First Name</th>
<th className="px-4 py-3 text-left">Last Name</th>
<th className="px-4 py-3 text-left">Email</th>
<th className="px-4 py-3 text-center">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
{loading ? (
<div className="overflow-y-auto max-h-[79vh] border border-gray-200 rounded shadow-sm no-scrollbar">
<table className="min-w-full text-sm bg-white">
<thead className="bg-gray-100 text-gray-700 uppercase text-xs tracking-wider sticky top-0 z-10">
<tr>
<td colSpan="4" className="text-center py-4">Loading...</td>
<th className="px-4 py-3 text-left">First Name</th>
<th className="px-4 py-3 text-left">Last Name</th>
<th className="px-4 py-3 text-left">Email</th>
<th className="px-4 py-3 text-center">Actions</th>
</tr>
) : contacts.length === 0 ? (
<tr>
<td colSpan="4" className="text-center py-4">No contacts found.</td>
</tr>
) : (
contacts.map((contact) => (
<tr key={contact.id} className="hover:bg-gray-50">
<td className="px-4 py-3">{contact.firstName}</td>
<td className="px-4 py-3">{contact.lastName}</td>
<td className="px-4 py-3">{contact.email}</td>
<td className="px-4 py-3 text-center">
<div
className="relative inline-block"
tabIndex={0}
onBlur={handleBlur}
>
<button
className="text-gray-600 hover:text-black p-1 focus:outline-none"
onClick={() => toggleMenu(contact.id)}
>
<FaEllipsisV />
</button>
{openMenuId === contact.id && (
<div className="absolute top-full right-0 mt-1 bg-white border border-gray-200 rounded shadow-lg z-20 min-w-[100px]">
<button
onMouseDown={() => handleEdit(contact.id)}
className="block w-full text-left px-4 py-2 text-sm hover:bg-gray-100 text-blue-600"
>
Edit
</button>
<button
onMouseDown={() => handleDelete(contact.id)}
className="block w-full text-left px-4 py-2 text-sm hover:bg-gray-100 text-red-600"
>
Delete
</button>
</div>
)}
</div>
</td>
</thead>
<tbody className="divide-y divide-gray-200">
{loading ? (
<tr>
<td colSpan="4" className="text-center py-4">Loading...</td>
</tr>
))
)}
</tbody>
</table>
{showModal &&
<ContactFormModal onSubmit={handleContactSubmit}
loading={createAndInviteLoader} setShowModal={setShowModal} actionStatus={actionStatus} editJsonData={editJsonData} />
}
) : contacts.length === 0 ? (
<tr>
<td colSpan="4" className="text-center py-4">No contacts found.</td>
</tr>
) : (
contacts.map((contact) => (
<tr key={contact.id} className="hover:bg-gray-50">
<td className="px-4 py-3">{contact.firstName}</td>
<td className="px-4 py-3">{contact.lastName}</td>
<td className="px-4 py-3">{contact.email}</td>
<td className="px-4 py-3 text-center">
<div
className="relative inline-block"
tabIndex={0}
onBlur={handleBlur}
>
<button
className="text-gray-600 hover:text-black p-1 focus:outline-none"
onClick={() => toggleMenu(contact.id)}
>
<FaEllipsisV />
</button>
{openMenuId === contact.id && (
<div className="absolute top-full right-0 mt-1 bg-white border border-gray-200 rounded shadow-lg z-20 min-w-[100px]">
<button
onMouseDown={() => handleEdit(contact.id)}
className="block w-full text-left px-4 py-2 text-sm hover:bg-gray-100 text-blue-600"
>
Edit
</button>
<button
onMouseDown={() => handleDelete(contact.id)}
className="block w-full text-left px-4 py-2 text-sm hover:bg-gray-100 text-red-600"
>
Delete
</button>
</div>
)}
</div>
</td>
</tr>
))
)}
</tbody>
</table>
{showModal &&
<ContactFormModal onSubmit={handleContactSubmit}
loading={createAndInviteLoader} setShowModal={setShowModal} actionStatus={actionStatus} editJsonData={editJsonData} />
}
</div>
</div>
</>
);

View File

@ -1,4 +1,3 @@
import React from 'react'
import { LuSignature } from "react-icons/lu";
import { useSelector } from 'react-redux';
import { RootState } from '../../store/store';

View File

@ -136,7 +136,15 @@ const Templates = () => {
</tr>
</thead>
{templates.length > 0 ? (
{loading ? (
<tbody>
<tr>
<td colSpan="6" className="relative h-100">
<LoaderUi />
</td>
</tr>
</tbody>
) : templates.length > 0 ? (
<tbody className="divide-y divide-gray-200">
{templates.map((item, index) => {
return (
@ -200,18 +208,12 @@ const Templates = () => {
) : (
<tbody>
<tr>
<td colSpan="5">
<div className="relative flex justify-center items-center h-100 w-full">
{/* Pulsing background div */}
<div className="absolute inset-0 bg-gradient-to-r from-gray-200 to-white animate-pulse"></div>
{/* Loader stays on top, no animation */}
<LoaderUi classStyle="relative h-16 w-16" />
</div>
<td colSpan="6" className="text-center py-10 text-gray-500">
No templates found.
</td>
</tr>
</tbody>
)}
</table>
</div>

View File

@ -1,19 +1,22 @@
import { LuSignature } from "react-icons/lu";
interface StyleProps {
classStyle : string
classStyle?: string;
}
const LoaderUi = ({ classStyle }:StyleProps) => {
return (
<div className={classStyle}>
<svg viewBox="0 0 240 240" height="240" width="240" className="pl">
<circle strokeLinecap="round" strokeDashoffset="-330" strokeDasharray="0 660" strokeWidth="20" stroke="#000" fill="none" r="105" cy="120" cx="120" className="pl__ring pl__ring--a"></circle>
<circle strokeLinecap="round" strokeDashoffset="-110" strokeDasharray="0 220" strokeWidth="20" stroke="#000" fill="none" r="35" cy="120" cx="120" className="pl__ring pl__ring--b"></circle>
<circle strokeLinecap="round" strokeDasharray="0 440" strokeWidth="20" stroke="#000" fill="none" r="70" cy="120" cx="85" className="pl__ring pl__ring--c"></circle>
<circle strokeLinecap="round" strokeDasharray="0 440" strokeWidth="20" stroke="#000" fill="none" r="70" cy="120" cx="155" className="pl__ring pl__ring--d"></circle>
</svg>
</div>
)
}
const LoaderUi = ({ classStyle = '' }: StyleProps) => {
return (
<div className={`absolute inset-0 flex items-center justify-center z-50 ${classStyle}`}>
{/* Overlay */}
<div className="absolute inset-0 bg-black/30 opacity-60"></div>
export default LoaderUi
{/* Loader box */}
<div className="relative z-10 bg-[var(--loaderBg)] flex flex-col justify-center items-center gap-2 px-16 py-8 rounded-md shadow-lg">
<LuSignature className="text-4xl font-bold animate-text" />
<p>Loading...!</p>
</div>
</div>
);
};
export default LoaderUi;