MISC
This commit is contained in:
@ -96,6 +96,11 @@ const sidemenu = [
|
||||
text: "Отчети",
|
||||
url: "/cart/reports/list",
|
||||
roles: [UserRole.ADMIN, UserRole.POWERUSER],
|
||||
// }, {
|
||||
// id: "statistics",
|
||||
// text: "Статистика",
|
||||
// url: "/cart/publishers/stats",
|
||||
// roles: [UserRole.ADMIN, UserRole.POWERUSER],
|
||||
},
|
||||
|
||||
]
|
||||
|
94
pages/cart/publishers/stats.tsx
Normal file
94
pages/cart/publishers/stats.tsx
Normal file
@ -0,0 +1,94 @@
|
||||
import { useState } from 'react';
|
||||
import Layout from "../../../components/layout";
|
||||
import ProtectedRoute from '../../../components/protectedRoute';
|
||||
import { UserRole } from '@prisma/client';
|
||||
import axiosServer from '../../../src/axiosServer';
|
||||
import common from '../../../src/helpers/common';
|
||||
import { filterPublishers, /* other functions */ } from '../../api/index';
|
||||
|
||||
function ContactsPage({ publishers }) {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
const filteredPublishers = publishers.filter((publisher) =>
|
||||
publisher.firstName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
publisher.lastName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
publisher.email.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
publisher.phone?.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER, UserRole.USER]}>
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="text-xl font-semibold mb-4">Контакти</h1>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Търси по име, имейл или телефон..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="border border-gray-300 rounded-md px-2 py-2 mb-4 w-full text-base md:text-sm"
|
||||
/>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="border-b font-medium p-4 pl-8 pt-0 pb-3">Име</th>
|
||||
<th className="border-b font-medium p-4 pt-0 pb-3">Имейл</th>
|
||||
<th className="border-b font-medium p-4 pt-0 pb-3">Телефон</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{filteredPublishers.map((publisher) => (
|
||||
<tr key={publisher.id}>
|
||||
<td className="border-b p-4 pl-8">{publisher.firstName} {publisher.lastName}</td>
|
||||
<td className="border-b p-4">
|
||||
<a href={`mailto:${publisher.email}`} className="text-blue-500">{publisher.email}</a>
|
||||
</td>
|
||||
<td className="border-b p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className={common.isValidPhoneNumber(publisher.phone) ? '' : 'text-red-500'}>{publisher.phone}</span>
|
||||
<div className="flex items-center">
|
||||
<a href={`tel:${publisher.phone}`} className="inline-block p-2 mr-2">
|
||||
<i className="fas fa-phone-alt text-blue-500 text-xl" title="Обаждане"></i>
|
||||
</a>
|
||||
<a href={`https://wa.me/${publisher.phone}`} className="inline-block p-2 mr-2">
|
||||
<i className="fab fa-whatsapp text-green-500 text-xl" title="WhatsApp"></i>
|
||||
</a>
|
||||
{publisher.phone ? (
|
||||
<a href={`viber://chat/?number=%2B${publisher.phone.startsWith('+') ? publisher.phone.substring(1) : publisher.phone}`} className="inline-block p-2">
|
||||
<i className="fab fa-viber text-purple-500 text-xl" title="Viber"></i>
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</ProtectedRoute>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default ContactsPage;
|
||||
|
||||
export const getServerSideProps = async (context) => {
|
||||
const dateStr = new Date().toISOString().split('T')[0];
|
||||
|
||||
let publishers = await filterPublishers('id,firstName,lastName,isactive,desiredShiftsPerMonth', "", new Date(), true, true);
|
||||
// const axios = await axiosServer(context);
|
||||
// const { data: publishers } = await axios.get(`api/?action=filterPublishers&assignments=true&availabilities=true&date=${dateStr}&select=id,firstName,lastName,isactive,desiredShiftsPerMonth`);
|
||||
|
||||
// api/index?action=filterPublishers&assignments=true&availabilities=true&date=2024-03-14&select=id%2CfirstName%2ClastName%2Cisactive%2CdesiredShiftsPerMonth
|
||||
|
||||
|
||||
return {
|
||||
props: {
|
||||
publishers,
|
||||
},
|
||||
};
|
||||
};
|
33
server.js
33
server.js
@ -39,8 +39,8 @@ const PORT = process.env.NEXT_PUBLIC_PORT || 3000;
|
||||
const HOST = process.env.NEXT_PUBLIC_HOST;
|
||||
const dev = process.env.NODE_ENV !== "production";
|
||||
const PROTOCOL = process.env.NEXT_PUBLIC_PROTOCOL;
|
||||
const app = next({ dev });
|
||||
const handle = app.getRequestHandler();
|
||||
const nextApp = next({ dev });
|
||||
const nextHandler = nextApp.getRequestHandler();
|
||||
console.log("process.env.SSL_ENABLED = ", process.env.SSL_ENABLED);
|
||||
console.log("process.env.NEXTAUTH_URL = ", process.env.NEXTAUTH_URL);
|
||||
console.log("process.env.NEXT_PUBLIC_PORT = ", process.env.NEXT_PUBLIC_PORT);
|
||||
@ -63,7 +63,7 @@ const uploadTmp = multer({ storage: storageMem });
|
||||
const prisma = common.getPrismaClient();
|
||||
|
||||
// handlers
|
||||
app
|
||||
nextApp
|
||||
.prepare()
|
||||
.then(() => {
|
||||
const server = express();
|
||||
@ -518,6 +518,13 @@ app
|
||||
|
||||
|
||||
|
||||
});
|
||||
//----------------- log client console messages and their session.user.id and IP----------------
|
||||
server.post("/log", (req, res) => {
|
||||
//get ip from request
|
||||
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||
console.log("[client log] " + req.body.message + " user: " + req.body.userId + " IP: " + ip);
|
||||
res.end("ok");
|
||||
});
|
||||
|
||||
// --------------- EXCEL EXPORT ROUTE ----------------
|
||||
@ -533,19 +540,19 @@ app
|
||||
});
|
||||
|
||||
server.get("*", (req, res) => {
|
||||
return handle(req, res);
|
||||
return nextHandler(req, res);
|
||||
});
|
||||
server.post("*", (req, res) => {
|
||||
return handle(req, res);
|
||||
return nextHandler(req, res);
|
||||
});
|
||||
server.put("*", (req, res) => {
|
||||
return handle(req, res);
|
||||
return nextHandler(req, res);
|
||||
});
|
||||
server.patch("*", (req, res) => {
|
||||
return handle(req, res);
|
||||
return nextHandler(req, res);
|
||||
});
|
||||
server.delete("*", (req, res) => {
|
||||
return handle(req, res);
|
||||
return nextHandler(req, res);
|
||||
});
|
||||
|
||||
//check if ssl is enabled
|
||||
@ -652,15 +659,7 @@ async function Stat() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Stat();
|
||||
|
||||
exports.baseUrlGlobal = baseUrlGlobal;
|
||||
|
||||
exports.default = app;
|
||||
exports.default = nextApp;
|
||||
|
Reference in New Issue
Block a user