Last active
February 6, 2023 01:35
-
-
Save AlexandroMtzG/2dba00f3446f8d89d819aa74fa8d5dca to your computer and use it in GitHub Desktop.
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
import { Fragment } from "react"; | |
import { DocumentDto } from "../dtos/DocumentDto"; | |
import { DocumentTypeDto } from "../dtos/DocumentTypeDto"; | |
interface Props { | |
year: number; | |
types: DocumentTypeDto[]; | |
documents: DocumentDto[]; | |
} | |
export default function AccountDocuments({ year, types, documents }: Props) { | |
function getDocumentsInPeriod(type: DocumentTypeDto, period: number): DocumentDto[] { | |
const yearDocuments = documents.filter((document) => document.year === year || !document.year); | |
const typeDocuments = yearDocuments.filter((document) => document.type.name === type.name); | |
const periodDocuments = typeDocuments.filter((document) => document.period === period || !document.period); | |
return periodDocuments; | |
} | |
function getDocumentTypePeriods(timesInYear: number | null): { from: Date; to: Date; name: string; number: number }[] { | |
let periods: { from: Date; to: Date; name: string; number: number }[] = []; | |
if (timesInYear === 1 !|| timesInYear) { | |
periods = [{ number: 1, name: "Jan-Dec", from: new Date(year, 0, 1), to: new Date(year, 11, 31) }]; | |
} else if (timesInYear === 2) { | |
periods = [ | |
{ number: 1, name: "Jan-Jun", from: new Date(year, 0, 1), to: new Date(year, 5, 30) }, | |
{ number: 2, name: "Jul-Dec", from: new Date(year, 6, 1), to: new Date(year, 11, 31) }, | |
]; | |
} else if (timesInYear === 4) { | |
// jan-mar, apr-jun, jul-sep, oct-dec | |
periods = [ | |
{ number: 1, name: "Jan-Mar", from: new Date(year, 0, 1), to: new Date(year, 2, 31) }, | |
{ number: 2, name: "Apr-Jun", from: new Date(year, 3, 1), to: new Date(year, 5, 30) }, | |
{ number: 3, name: "Jul-Sep", from: new Date(year, 6, 1), to: new Date(year, 8, 30) }, | |
{ number: 4, name: "Oct-Dec", from: new Date(year, 9, 1), to: new Date(year, 11, 31) }, | |
]; | |
} else if (timesInYear === 6) { | |
// jan-feb, mar-apr, may-jun, jul-aug, sep-oct, nov-dec | |
periods = [ | |
{ number: 1, name: "Jan-Feb", from: new Date(year, 0, 1), to: new Date(year, 1, 28) }, | |
{ number: 2, name: "Mar-Apr", from: new Date(year, 2, 1), to: new Date(year, 3, 30) }, | |
{ number: 3, name: "May-Jun", from: new Date(year, 4, 1), to: new Date(year, 5, 30) }, | |
{ number: 4, name: "Jul-Aug", from: new Date(year, 6, 1), to: new Date(year, 7, 31) }, | |
{ number: 5, name: "Sep-Oct", from: new Date(year, 8, 1), to: new Date(year, 9, 30) }, | |
{ number: 6, name: "Nov-Dec", from: new Date(year, 10, 1), to: new Date(year, 11, 31) }, | |
]; | |
} else if (timesInYear === 12) { | |
periods = Array.from(Array(12).keys()).map((idx) => ({ | |
number: idx + 1, | |
name: getMonthName(idx + 1), | |
from: new Date(year, idx, 1), | |
to: new Date(year, idx + 1, 0), | |
})); | |
} | |
return periods; | |
} | |
function getMonthName(month: number): string { | |
const months: string[] = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; | |
if (month >= 1 && month <= 12) { | |
return months[month - 1].substring(0, 3); | |
} | |
return ""; | |
} | |
function getDocumentTypeTimeline(type: DocumentTypeDto, period: number): "past" | "current" | "future" { | |
const today = new Date(); | |
const periods = getDocumentTypePeriods(type.timesInYear); | |
const currentPeriod = periods.find((period) => period.from <= today && period.to >= today); | |
if (year < today.getFullYear()) { | |
return "past"; | |
} | |
if (year > today.getFullYear()) { | |
return "future"; | |
} | |
if (currentPeriod && currentPeriod.number === period) { | |
return "current"; | |
} else if (currentPeriod && currentPeriod.number > period) { | |
return "past"; | |
} | |
return "future"; | |
} | |
function getDocumentInPeriodStatus(type: DocumentTypeDto, period: number): "valid" | "pending" | "n/a" | "missing" { | |
const documentsInPeriod = getDocumentsInPeriod(type, period); | |
const timeline = getDocumentTypeTimeline(type, period); | |
if (documentsInPeriod.length > 0) { | |
return "valid"; | |
} | |
if (!type.timesInYear || timeline === "past") { | |
return "missing"; | |
} | |
if (timeline === "future") { | |
return "n/a"; | |
} | |
if (timeline === "current") { | |
return "pending"; | |
} | |
return "missing"; | |
} | |
function isCurrentMonth(month: number): boolean { | |
const today = new Date(); | |
return today.getFullYear() === year && today.getMonth() + 1 === month; | |
} | |
return ( | |
<div className="overflow-x-auto rounded-lg border border-gray-200 bg-white"> | |
<table className="w-full"> | |
<thead> | |
<tr> | |
<th rowSpan={2} className="border border-gray-200 bg-gray-100 text-gray-600 text-left text-sm font-bold px-4 py-2 w-full"> | |
Document Type | |
</th> | |
{Array.from(Array(12).keys()).map((idx) => ( | |
<Fragment key={idx}> | |
<th className="border border-gray-200 bg-gray-100 text-gray-600 text-center text-sm px-4 py-2 w-1/12"> | |
<div className="flex"> | |
<div className="font-bold">{getMonthName(idx + 1)}</div> | |
{isCurrentMonth(idx + 1) && ( | |
<div className="text-xs text-theme-400 font-medium lowercase"> | |
<span className="text-red-500 flex-shrink-0 inline-flex items-center p-1 rounded-full text-xs font-medium"> | |
<svg className="h-2 w-2" fill="currentColor" viewBox="0 0 8 8"> | |
<circle cx={4} cy={4} r={3} /> | |
</svg> | |
</span> | |
</div> | |
)} | |
</div> | |
</th> | |
</Fragment> | |
))} | |
</tr> | |
</thead> | |
<tbody> | |
{types.map((type) => ( | |
<tr key={type.name}> | |
<td className="border border-gray-200 text-gray-600 text-left text-sm px-4 py-2 truncate">{type.name}</td> | |
{getDocumentTypePeriods(type.timesInYear).map((_, idx) => ( | |
<td key={idx} className="text-gray-600 text-center text-sm border" colSpan={12 / getDocumentTypePeriods(type.timesInYear).length}> | |
<DocumentPeriodStatus status={getDocumentInPeriodStatus(type, idx + 1)} /> | |
{/* <TimelineBadge timeline={getDocumentTypeTimeline(type, idx + 1)} /> */} | |
</td> | |
))} | |
</tr> | |
))} | |
</tbody> | |
</table> | |
</div> | |
); | |
} | |
function DocumentPeriodStatus({ status }: { status: "valid" | "pending" | "n/a" | "missing" }) { | |
return ( | |
<> | |
{status === "valid" && <div className="bg-teal-100 text-teal-800 text-xs font-bold w-full py-3 h-10">✓</div>} | |
{status === "missing" && <div className="bg-red-100 text-red-800 text-xs font-bold w-full py-3 h-10">✗</div>} | |
{status === "n/a" && <div className="bg-gray-200 text-gray-800 text-xs font-bold w-full py-3 h-10"></div>} | |
{status === "pending" && ( | |
<div className="bg-white text-xs font-bold w-full py-3 h-10 flex justify-center text-gray-800"> | |
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" className="w-4 h-4"> | |
<path d="M9.25 13.25a.75.75 0 001.5 0V4.636l2.955 3.129a.75.75 0 001.09-1.03l-4.25-4.5a.75.75 0 00-1.09 0l-4.25 4.5a.75.75 0 101.09 1.03L9.25 4.636v8.614z" /> | |
<path d="M3.5 12.75a.75.75 0 00-1.5 0v2.5A2.75 2.75 0 004.75 18h10.5A2.75 2.75 0 0018 15.25v-2.5a.75.75 0 00-1.5 0v2.5c0 .69-.56 1.25-1.25 1.25H4.75c-.69 0-1.25-.56-1.25-1.25v-2.5z" /> | |
</svg> | |
</div> | |
)} | |
</> | |
); | |
} | |
function TimelineBadge({ timeline }: { timeline: "past" | "current" | "future" }) { | |
return ( | |
<> | |
{timeline === "past" && <div className="bg-orange-100 text-orange-800 text-xs font-bold w-full h-10 py-3">Past</div>} | |
{timeline === "current" && <div className="bg-teal-100 text-teal-800 text-xs font-bold w-full h-10 py-3">Current</div>} | |
{timeline === "future" && <div className="bg-gray-100 text-gray-800 text-xs font-bold w-full h-10 py-3">Future</div>} | |
</> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment