Fix mobile and date
This commit is contained in:
parent
ca1bafbb16
commit
7bc32acafb
3 changed files with 73 additions and 34 deletions
|
|
@ -7,6 +7,23 @@ import Joi from 'joi';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
// Helper function to normalize date input to avoid timezone issues
|
||||||
|
function normalizeDate(dateInput: any): Date {
|
||||||
|
if (typeof dateInput === 'string') {
|
||||||
|
// If it's a string in YYYY-MM-DD format, create date in local time
|
||||||
|
const [year, month, day] = dateInput.split('-');
|
||||||
|
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
||||||
|
}
|
||||||
|
if (dateInput instanceof Date) {
|
||||||
|
// If it's already a Date object, extract date parts and recreate to avoid timezone issues
|
||||||
|
const year = dateInput.getFullYear();
|
||||||
|
const month = dateInput.getMonth();
|
||||||
|
const day = dateInput.getDate();
|
||||||
|
return new Date(year, month, day);
|
||||||
|
}
|
||||||
|
return dateInput;
|
||||||
|
}
|
||||||
|
|
||||||
// Validation schemas
|
// Validation schemas
|
||||||
const createDocketEntrySchema = Joi.object({
|
const createDocketEntrySchema = Joi.object({
|
||||||
date: Joi.date().required(),
|
date: Joi.date().required(),
|
||||||
|
|
@ -89,8 +106,14 @@ router.post('/', authenticateToken, asyncHandler(async (req: AuthenticatedReques
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize date to avoid timezone issues
|
||||||
|
const normalizedData = { ...value };
|
||||||
|
if (value.date) {
|
||||||
|
normalizedData.date = normalizeDate(value.date);
|
||||||
|
}
|
||||||
|
|
||||||
const entry = await prisma.docketEntry.create({
|
const entry = await prisma.docketEntry.create({
|
||||||
data: value,
|
data: normalizedData,
|
||||||
include: {
|
include: {
|
||||||
documents: {
|
documents: {
|
||||||
orderBy: {
|
orderBy: {
|
||||||
|
|
@ -139,10 +162,16 @@ router.put('/:id', authenticateToken, asyncHandler(async (req: AuthenticatedRequ
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize date to avoid timezone issues
|
||||||
|
const normalizedData = { ...value };
|
||||||
|
if (value.date) {
|
||||||
|
normalizedData.date = normalizeDate(value.date);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const entry = await prisma.docketEntry.update({
|
const entry = await prisma.docketEntry.update({
|
||||||
where: { id: entryId },
|
where: { id: entryId },
|
||||||
data: value,
|
data: normalizedData,
|
||||||
include: {
|
include: {
|
||||||
documents: {
|
documents: {
|
||||||
orderBy: {
|
orderBy: {
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,23 @@ export default function HomePage() {
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
const [isMobile, setIsMobile] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchDocketEntries();
|
fetchDocketEntries();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const checkMobile = () => {
|
||||||
|
setIsMobile(window.innerWidth < 768);
|
||||||
|
};
|
||||||
|
|
||||||
|
checkMobile();
|
||||||
|
window.addEventListener('resize', checkMobile);
|
||||||
|
|
||||||
|
return () => window.removeEventListener('resize', checkMobile);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const fetchDocketEntries = async () => {
|
const fetchDocketEntries = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/docket-entries');
|
const response = await fetch('/api/docket-entries');
|
||||||
|
|
@ -94,7 +106,18 @@ export default function HomePage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatDate = (dateString: string) => {
|
const formatDate = (dateString: string) => {
|
||||||
return new Date(dateString).toLocaleDateString('en-US', {
|
// Extract date parts directly to avoid timezone conversion issues
|
||||||
|
const datePart = dateString.split('T')[0]; // Get just YYYY-MM-DD part
|
||||||
|
if (!datePart) return 'Invalid Date';
|
||||||
|
|
||||||
|
const parts = datePart.split('-');
|
||||||
|
if (parts.length !== 3) return 'Invalid Date';
|
||||||
|
|
||||||
|
const [year, month, day] = parts;
|
||||||
|
if (!year || !month || !day) return 'Invalid Date';
|
||||||
|
|
||||||
|
const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
||||||
|
return date.toLocaleDateString('en-US', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
|
|
@ -103,10 +126,26 @@ export default function HomePage() {
|
||||||
|
|
||||||
const getLastUpdated = () => {
|
const getLastUpdated = () => {
|
||||||
if (docketEntries.length === 0) return 'No entries';
|
if (docketEntries.length === 0) return 'No entries';
|
||||||
const latest = docketEntries[docketEntries.length - 1];
|
const latest = docketEntries.length > 0 ? docketEntries[docketEntries.length - 1] : null;
|
||||||
return latest ? formatDate(latest.date) : 'No entries';
|
return latest ? formatDate(latest.date) : 'No entries';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDocumentClick = (doc: Document) => {
|
||||||
|
const documentUrl = `/api/documents/${doc.id}/download`;
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
// On mobile, open PDF directly in new tab (MCDI approach)
|
||||||
|
window.open(documentUrl, '_blank');
|
||||||
|
} else {
|
||||||
|
// On desktop, use modal viewer
|
||||||
|
setSelectedDocument({
|
||||||
|
id: doc.id,
|
||||||
|
title: doc.title,
|
||||||
|
url: documentUrl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center bg-white">
|
<div className="min-h-screen flex items-center justify-center bg-white">
|
||||||
|
|
@ -446,11 +485,7 @@ export default function HomePage() {
|
||||||
.map((doc) => (
|
.map((doc) => (
|
||||||
<div key={doc.id} className="flex items-center justify-center p-3 bg-gray-50 rounded-lg">
|
<div key={doc.id} className="flex items-center justify-center p-3 bg-gray-50 rounded-lg">
|
||||||
<button
|
<button
|
||||||
onClick={() => setSelectedDocument({
|
onClick={() => handleDocumentClick(doc)}
|
||||||
id: doc.id,
|
|
||||||
title: doc.title,
|
|
||||||
url: `/api/documents/${doc.id}/download`
|
|
||||||
})}
|
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-flex',
|
display: 'inline-flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,6 @@ const PDFViewer: React.FC<PDFViewerProps> = ({
|
||||||
documentTitle,
|
documentTitle,
|
||||||
documentUrl
|
documentUrl
|
||||||
}) => {
|
}) => {
|
||||||
const [isMobile, setIsMobile] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const checkMobile = () => {
|
|
||||||
setIsMobile(window.innerWidth < 768);
|
|
||||||
};
|
|
||||||
|
|
||||||
checkMobile();
|
|
||||||
window.addEventListener('resize', checkMobile);
|
|
||||||
|
|
||||||
return () => window.removeEventListener('resize', checkMobile);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
|
|
@ -53,18 +40,6 @@ const PDFViewer: React.FC<PDFViewerProps> = ({
|
||||||
window.open(documentUrl, '_blank');
|
window.open(documentUrl, '_blank');
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
// On mobile, just open the PDF in a new tab and close the modal
|
|
||||||
useEffect(() => {
|
|
||||||
if (isOpen && isMobile) {
|
|
||||||
window.open(documentUrl, '_blank');
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
}, [isOpen, isMobile, documentUrl, onClose]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue