initial commit - code moved to separate repo
This commit is contained in:
179
components/reports/ExperienceForm.js
Normal file
179
components/reports/ExperienceForm.js
Normal file
@ -0,0 +1,179 @@
|
||||
import axiosInstance from '../../src/axiosSecure';
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from 'react-toastify';
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
import DayOfWeek from "../DayOfWeek";
|
||||
import { Location, UserRole } from "@prisma/client";
|
||||
const common = require('src/helpers/common');
|
||||
|
||||
import { useSession } from "next-auth/react"
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
const ReactQuill = dynamic(() => import('react-quill'), {
|
||||
ssr: false,
|
||||
loading: () => <p>Loading...</p>,
|
||||
});
|
||||
import 'react-quill/dist/quill.snow.css'; // import styles
|
||||
|
||||
// ------------------ ExperienceForm ------------------
|
||||
// This component is used to create and edit
|
||||
// model:
|
||||
// model Report {
|
||||
// id Int @id @default(autoincrement())
|
||||
// date DateTime
|
||||
// publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade)
|
||||
// publisherId String
|
||||
// assignment Assignment @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
|
||||
// assignmentId Int
|
||||
|
||||
// placementCount Int?
|
||||
// videoCount Int?
|
||||
// returnVisitInfoCount Int?
|
||||
// conversationCount Int?
|
||||
|
||||
// experienceInfo String?
|
||||
// }
|
||||
|
||||
export default function ExperienceForm({ publisherId, assgnmentId, existingItem, onDone }) {
|
||||
const { data: session, status } = useSession()
|
||||
const [pubId, setPublisher] = useState(publisherId);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
//get the user from session if publisherId is null
|
||||
useEffect(() => {
|
||||
if (!publisherId) {
|
||||
if (session) {
|
||||
setPublisher(session.user.id);
|
||||
}
|
||||
}
|
||||
}, [publisherId, session]);
|
||||
|
||||
const [item, setItem] = useState(existingItem || {
|
||||
experienceInfo: "",
|
||||
assignmentId: assgnmentId,
|
||||
publisherId: publisherId,
|
||||
date: new Date(),
|
||||
placementCount: 0,
|
||||
videoCount: 0,
|
||||
returnVisitInfoCount: 0,
|
||||
conversationCount: 0
|
||||
});
|
||||
|
||||
const [locations, setLocations] = useState([]);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const fetchLocations = async () => {
|
||||
try {
|
||||
console.log("fetching locations");
|
||||
const { data } = await axiosInstance.get("/api/data/locations");
|
||||
setLocations(data);
|
||||
item.locationId = data[0].id;
|
||||
console.log(data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
if (!locations.length) {
|
||||
fetchLocations();
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
const handleLocationChange = ({ target }) => {
|
||||
setItem({ ...item, [target.name]: target.value });
|
||||
};
|
||||
|
||||
const handleChange = (content, delta, source, editor) => {
|
||||
item.experienceInfo = content;
|
||||
setItem(item);
|
||||
console.log(editor.getHTML()); // rich text
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
item.publisher = { connect: { id: pubId } };
|
||||
item.location = { connect: { id: parseInt(item.locationId) } };
|
||||
delete item.locationId;
|
||||
|
||||
try {
|
||||
const response = await axiosInstance.post('/api/data/reports', item);
|
||||
console.log(response);
|
||||
toast.success("Случката е записана. Благодарим Ви!");
|
||||
setTimeout(() => {
|
||||
if (onDone) {
|
||||
onDone();
|
||||
} else {
|
||||
router.push(`/dash`);
|
||||
}
|
||||
}, 3000); // Delay for 3 seconds
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("Error saving report");
|
||||
}
|
||||
}
|
||||
|
||||
const modules = {
|
||||
toolbar: {
|
||||
container: [
|
||||
['bold', 'italic', 'underline'], // Basic text formats
|
||||
[{ 'list': 'ordered' }, { 'list': 'bullet' }], // Lists
|
||||
['link', 'image'] // Media
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-md mx-auto">
|
||||
<form className="bg-white dark:bg-gray-800 shadow rounded-lg px-8 pt-6 pb-8 mb-4" onSubmit={handleSubmit} >
|
||||
|
||||
<div className="mb-4">
|
||||
<label className='block text-gray-700 dark:text-gray-300 text-sm font-bold mb-2' htmlFor="location">Място</label>
|
||||
{locations && (
|
||||
<select
|
||||
name="locationId"
|
||||
id="locationId"
|
||||
value={item.locationId}
|
||||
onChange={handleLocationChange}
|
||||
className="block appearance-none w-full bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded py-2 px-3 text-gray-700 dark:text-gray-300 leading-tight focus:outline-none focus:bg-white focus:border-blue-500"
|
||||
>
|
||||
{locations.map((loc) => (
|
||||
<option key={loc.id} value={loc.id}>{loc.name}</option>
|
||||
))}
|
||||
</select>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="mb-8"> {/* Increased bottom margin */}
|
||||
<label className="block text-gray-700 dark:text-gray-300 text-sm font-bold mb-2" htmlFor="experienceInfo">
|
||||
Насърчителна случка
|
||||
</label>
|
||||
<ReactQuill
|
||||
theme="snow"
|
||||
value={item.experienceInfo}
|
||||
onChange={handleChange}
|
||||
modules={modules}
|
||||
className="w-full h-60 pb-6 bg-white dark:bg-gray-700"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row items-center justify-between mt-"> {/* Adjusted layout and added top margin */}
|
||||
<Link href={`/dash`} className="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800 mt-4 md:mt-0">
|
||||
Отказ
|
||||
</Link>
|
||||
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit">
|
||||
Запази
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
180
components/reports/ReportForm.js
Normal file
180
components/reports/ReportForm.js
Normal file
@ -0,0 +1,180 @@
|
||||
import axiosInstance from '../../src/axiosSecure';
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
import { useSession } from "next-auth/react"
|
||||
|
||||
const common = require('src/helpers/common');
|
||||
|
||||
|
||||
// ------------------ ------------------
|
||||
// This component is used to create and edit
|
||||
/* location model:
|
||||
|
||||
model Report {
|
||||
id Int @id @default(autoincrement())
|
||||
date DateTime
|
||||
publisherId String
|
||||
publisher Publisher @relation(fields: [publisherId], references: [id], onDelete: Cascade)
|
||||
locationId Int?
|
||||
location Location? @relation(fields: [locationId], references: [id])
|
||||
shift Shift?
|
||||
|
||||
placementCount Int?
|
||||
videoCount Int?
|
||||
returnVisitInfoCount Int?
|
||||
conversationCount Int?
|
||||
|
||||
experienceInfo String? @db.LongText
|
||||
}
|
||||
*/
|
||||
|
||||
export default function ReportForm({ shiftId, existingItem, onDone }) {
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const getFormattedDate = (date) => {
|
||||
let year = date.getFullYear();
|
||||
let month = (1 + date.getMonth()).toString().padStart(2, '0');
|
||||
let day = date.getDate().toString().padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
const initialDate = getFormattedDate(new Date());
|
||||
const { data: session, status } = useSession()
|
||||
const [publisherId, setPublisher] = useState(null);
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
setPublisher(session.user.id);
|
||||
}
|
||||
}, [session]);
|
||||
|
||||
|
||||
const [item, setItem] = useState(existingItem || {
|
||||
experienceInfo: "",
|
||||
date: existingItem?.date || initialDate,
|
||||
shiftId: shiftId,
|
||||
publisherId: publisherId,
|
||||
placementCount: 0,
|
||||
videoCount: 0,
|
||||
returnVisitInfoCount: 0,
|
||||
conversationCount: 0
|
||||
});
|
||||
const [shifts, setShifts] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const dateStr = common.getISODateOnly(new Date(item.date));
|
||||
const { data: shiftsForDate } = await axiosInstance.get(`/api/?action=getShiftsForDay&date=${dateStr}`);
|
||||
setShifts(shiftsForDate);
|
||||
if (!existingItem && shiftsForDate.length > 0) {
|
||||
setItem((prevItem) => ({ ...prevItem, shiftId: shiftsForDate[0].id }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
}, [item.date, existingItem]);
|
||||
const handleChange = ({ target }) => {
|
||||
setItem({ ...item, [target.name]: target.value });
|
||||
};
|
||||
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
item.publisher = { connect: { id: publisherId } };
|
||||
item.shift = { connect: { id: parseInt(item.shiftId) } };
|
||||
item.date = new Date(item.date);
|
||||
delete item.publisherId;
|
||||
delete item.shiftId;
|
||||
item.placementCount = parseInt(item.placementCount);
|
||||
item.videoCount = parseInt(item.videoCount);
|
||||
item.returnVisitInfoCount = parseInt(item.returnVisitInfoCount);
|
||||
item.conversationCount = parseInt(item.conversationCount);
|
||||
// item.location = { connect: { id: parseInt(item.locationId) } };s
|
||||
console.log("handleSubmit");
|
||||
console.log(item);
|
||||
try {
|
||||
const response = await axiosInstance.post('/api/data/reports', item);
|
||||
console.log(response);
|
||||
toast.success("Гоово. Благодарим Ви за отчета!");
|
||||
setTimeout(() => {
|
||||
if (onDone) {
|
||||
onDone();
|
||||
} else {
|
||||
router.push(`/dash`);
|
||||
}
|
||||
}, 300); // Delay for 3 seconds
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toast.error("За съжаление възникна грешка!");
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-md mx-auto">
|
||||
{/* <iframe src="https://docs.google.com/forms/d/e/1FAIpQLSdjbqgQEGY5-fA4A0B4cXjKRQVRWk5_-uoHVIAwdMcZ5bB7Zg/viewform?embedded=true" width="640" height="717" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe> */}
|
||||
|
||||
<form className="bg-white dark:bg-gray-800 shadow-md rounded px-8 pt-6 pb-8 mb-4" onSubmit={handleSubmit} >
|
||||
|
||||
<h1 className="text-2xl font-bold mb-8">Отчет от смяна</h1>
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="date">
|
||||
Дата
|
||||
</label>
|
||||
<input className="textbox form-input px-4 py-2 rounded" id="date" name="date" type="date" onChange={handleChange} value={item.date} autoComplete="off" />
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="shiftId">
|
||||
Смяна
|
||||
</label>
|
||||
<select className="textbox form-select px-4 py-2 rounded"
|
||||
id="shiftId" name="shiftId" onChange={handleChange} value={item.shiftId} autoComplete="off" >
|
||||
{shifts.map((shift) => (
|
||||
<option key={shift.id} value={shift.id}>
|
||||
{shift.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="placementCount">
|
||||
Издания
|
||||
</label>
|
||||
<input className="textbox form-input px-4 py-2 rounded" id="placementCount" name="placementCount" type="number" onChange={handleChange} value={item.placementCount} autoComplete="off" />
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="conversationCount">
|
||||
Разговори
|
||||
</label>
|
||||
<input className="textbox form-input px-4 py-2 rounded" id="conversationCount" name="conversationCount" type="number" onChange={handleChange} value={item.conversationCount} autoComplete="off" />
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="videoCount">
|
||||
Клипове
|
||||
</label>
|
||||
<input className="textbox form-input px-4 py-2 rounded" id="videoCount" name="videoCount" type="number" onChange={handleChange} value={item.videoCount} autoComplete="off" />
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="returnVisitInfoCount">
|
||||
Адреси / Телефони
|
||||
</label>
|
||||
<input className="textbox form-input px-4 py-2 rounded" id="returnVisitInfoCount" name="returnVisitInfoCount" type="number" onChange={handleChange} value={item.returnVisitInfoCount} autoComplete="off" />
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" type="submit">
|
||||
Запази
|
||||
</button>
|
||||
<Link href={`/dash`}>
|
||||
Отказ
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user