Skip to content

Commit

Permalink
iniziato ProposalPdf
Browse files Browse the repository at this point in the history
  • Loading branch information
paolini committed Jan 31, 2024
1 parent c6153e1 commit b11da27
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 40 deletions.
11 changes: 7 additions & 4 deletions frontend/src/pages/ProposalPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export default function ProposalPage() {
const curriculum = curriculumQuery.data
const owner = (user && user?._id === proposal?.user_id)

if (query.isError) return <LoadingMessage>errore caricamento piano di studi... [{`${query.error}`}]</LoadingMessage>

if (!proposal || (proposal?.curriculum_id && (curriculum === null || degree === null))) {
return <LoadingMessage>caricamento piano di studi...</LoadingMessage>
}
Expand Down Expand Up @@ -119,13 +121,14 @@ export default function ProposalPage() {
}

function DownloadButtons() {
if (!proposal) return
return <>
<a className="d-none d-md-inline" href="">
<a className="d-none d-md-inline" href={`/proposals/${proposal._id}/pdf`}>
<Button className="button-sm mr-2">
<i className="fas fa-file-pdf"></i> Scarica come PDF
</Button>
</a>
<a className="d-none d-md-inline" href="">
<a className="d-none d-md-inline" href={`/proposals/${proposal._id}/pdf?comments=1`}>
<Button className="button-sm">
<i className="fas fa-file-pdf mr-2"></i>PDF inclusi i commenti
</Button>
Expand All @@ -135,10 +138,10 @@ export default function ProposalPage() {
<i className="fas fa-file-pdf"></i>
</Button>
<div className="dropdown-menu p-3">
<a className="dropdown-item" href="">
<a className="dropdown-item" href={`/proposals/${proposal._id}/pdf`}>
<i className="fas fa-file-pdf"></i> Scarica come PDF
</a>
<a className="dropdown-item" href="">
<a className="dropdown-item" href={`/proposals/${proposal._id}/pdf?comments=1`}>
<i className="fas fa-file-pdf"></i> PDF inclusi i commenti
</a>
</div>
Expand Down
180 changes: 180 additions & 0 deletions frontend/src/pages/ProposalPagePdf.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import React from 'react'
import { useParams } from "react-router-dom"

import {
useGetProposal,
useGetDegree, useGetCurriculum, useGetExam,
useEngine, useIndex,
} from '../modules/engine'
import LoadingMessage from '../components/LoadingMessage'
import Card from '../components/Card'
import {formatDate,displayAcademicYears} from '../modules/utils'
import StateBadge from '../components/StateBadge'

export default function ProposalPagePdf() {
const engine = useEngine()
const user = engine.user
const { id } = useParams()
const proposalQuery = useGetProposal(id)
const settingsQuery = useIndex(['settings'], {})
const settings: any = settingsQuery.data
const proposal = proposalQuery.data
const curriculumQuery = useGetCurriculum(proposal?.curriculum_id)
const curriculum = curriculumQuery.data
const owner = (user && user?._id === proposal?.user_id)

if (proposalQuery.isLoading || settingsQuery.isLoading || curriculumQuery.isLoading) {
return <LoadingMessage>caricamento piano di studi...</LoadingMessage>
}

if (!proposal) return <div>Errore caricamento proposal</div>
if (!settings) return <div>Errore caricamento settings</div>
if (!curriculum) return <div>Errore caricamento curriculum</div>

return <div id="content-wrapper" className="d-flex flex-column" style={{
fontFamily: "Helvetica",
fontSize: "0.7rem",
margin: "0.8cm",
marginBottom: "0.4cm",
}}>
<table>
<tr>
<td style={{width:"1%"}}><img src="/img/cherubino.png" width="100px"/></td>
<TdHeading>
<H2>{settings.department}</H2>
<H2>{proposal.degree_name}</H2>
<H2>Anno Accademico {guessAcademicYears(proposal)}</H2>
</TdHeading>
</tr>
</table>
<div style={{paddingTop:"1ex", fontSize: "14pt"}}>
<strong>Curriculum</strong>: {proposal.curriculum_name}<br />
<strong>Anno di immatricolazione</strong>: {proposal.degree_academic_year}<br />
<strong>Nome e cognome</strong>: {proposal.user_first_name} {proposal.user_last_name}<br />
<strong>Matricola</strong>: {proposal.user_id_number}<br />
<strong>Email</strong>: {proposal.user_email}<br />
</div>
{proposal && <MessageCard />}
{proposal && <InfoCard />}
{ proposal?.exams?.map((year_exams, index) => <Year key={index} number={index} exams={year_exams}/>)}
</div>

function TdHeading({children}) {
return <td style={{
padding: "6px",
paddingRight: "0.5cm",
border: "none",
}}>{children}</td>
}

function H2({children}) {
return <h2 style={{
fontSize: "15pt",
fontWeight: "normal",
}}>{children}</h2>
}

function guessAcademicYears(proposal) {
let date = proposal?.date_managed || proposal?.date_submitted || proposal.date_modified
if (!date) return "---"
date = new Date(date)
let year = date.getFullYear()
const month = date.getMonth()
if (month <= 8) year--
return `${year}/${year+1}`
}

function MessageCard() {
if (!proposal) return null
return <Card className={
{
'draft': "border-left-primary",
'submitted': "border-left-warning",
'approved': "border-left-success",
'rejected': "border-left-error",
}[proposal.state]
}>{
{
draft: `Questo piano è in stato di bozza. Devi inviarlo per avere l'approvazione.`,
submitted: `Il piano è stato inviato in data ${formatDate(proposal.date_submitted)}. ${owner?'Riceverai un email quando verrà approvato o rifiutato.':''}`,
approved: `Il piano è stato approvato in data ${formatDate(proposal.date_managed)}.`,
rejected: `Il piano è stato rigettato in data ${formatDate(proposal.date_managed)}. Puoi farne una copia, modificarlo e inviarlo nuovamente.`,
}[proposal.state]
}</Card>
}

function ExamRow({ exam }) {
const query = useGetExam(exam ? exam.exam_id : null)
if (query.isLoading) return <tr><td>loading...</td></tr>
if (query.isError) return <tr><td>error...</td></tr>
const real_exam: any = query.data
return <tr>
<td>{exam?.exam_code || '---'}</td>
<td>{exam?.exam_name || '---'}
{real_exam && real_exam.tags.map(tag =>
<div key={tag} className="badge ml-1 badge-secondary badge-sm">
{tag}
</div>)}
</td>
<td>{exam?.exam_sector || '---'}</td>
<td>{exam?.exam_credits || '---'}</td>
<td>{exam ? {
'CompulsoryExam': 'Obbligatorio',
'CompulsoryGroup': exam.group,
'FreeChoiceGroup': 'A scelta libera (G)',
'FreeChoiceExam': 'A scelta libera',
'ExternalExam': 'Esame Esterno',
}[exam.__t] : '---'}
</td>
</tr>
}

function Year({number, exams}) {
const yearName = ["Primo", "Secondo", "Terzo"][number] || `#${number}`

return <Card title={`${yearName} anno`}>
<table className="table">
<thead>
<tr>
<th>Codice</th>
<th>Nome</th>
<th>Settore</th>
<th>Crediti</th>
<th>Gruppo</th>
</tr>
</thead>
<tbody>
{ exams.map((e,i) => <ExamRow key={`exam-${number}-${i}`} exam={e}/>) }
</tbody>
</table>
</Card>
}

function InfoCard() {
if (!proposal) return null
return <Card>
<div className="d-flex mb-2">
<div className="flex-fill" />
</div>
<table className="table"><tbody>
<tr>
<th>Stato</th>
<td><StateBadge state={proposal.state} /></td>
</tr>
<tr>
<th>Corso di Laurea</th>
<td>{proposal.degree_name}</td>
</tr>
<tr>
<th>Curriculum</th>
<td>{proposal.curriculum_name}</td>
</tr>
<tr>
<th>Anno di immatricolazione</th>
<td>{displayAcademicYears(proposal.degree_academic_year)}</td>
</tr>
</tbody></table>
</Card>
}
}

2 changes: 1 addition & 1 deletion frontend/src/pages/ProposalsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function ProposalsPage() {
function renderCells(item: ProposalGet) {
return <>
<td><StateBadge state={item.state}/></td>
<td><a href={item.user_id}>{item.user_name}</a></td>
<td><a href={item._id}>{item.user_name}</a></td>
<td>{item.degree_academic_year}</td>
<td>{item.degree_name}</td>
<td>{item.curriculum_name}</td>
Expand Down
83 changes: 48 additions & 35 deletions frontend/src/pages/SinglePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import {
} from "react-router-dom"
import axios from 'axios'

import {useCreateEngine, EngineProvider} from '../modules/engine'
import {useEngine, useCreateEngine, EngineProvider} from '../modules/engine'

import ProposalsPage from "./ProposalsPage"
import { default as ProposalPage, EditProposalPage, NewProposalPage } from "./ProposalPage"
import ProposalPagePdf from "./ProposalPagePdf"
import FormsPage from "./FormsPage"
import FormPage from "./FormPage"
import DegreesPage from "./DegreesPage"
Expand Down Expand Up @@ -61,7 +62,6 @@ export default function SinglePage({config}) {
function SinglePageInternal({config}) {
const engine = useCreateEngine(config)
// engine.sync(useState(engine.state))
const modalConfirmData = engine.state.modalConfirmData

useEffect(engine.connect, [])
if (!engine.state.connected) return <LoadingMessage>connecting...</LoadingMessage>
Expand All @@ -70,39 +70,12 @@ function SinglePageInternal({config}) {
return <EngineProvider value={engine}>
<div id="wrapper">
<BrowserRouter>
<NavBar/>
<div id="content-wrapper" className="d-flex flex-column">
<TopBar/>
<Modal title={ modalConfirmData.title } content={ modalConfirmData.content } callback={ modalConfirmData.callback }></Modal>
<Flash messages={ engine.state.flashMessages } onClick={ () => engine.hideFlash() }></Flash>
<div id="content" className="px-4">
<Routes>
<Route path="/" element={<Splash/>}/>
<Route path="/index.html" element={<Splash/>}/>
<Route path="/proposals/edit/:id" element={<EditProposalPage/>}/>
<Route path="/proposals/:id" element={<ProposalPage/>}/>
<Route path="/proposals" element={<ProposalsPage/>}/>
{/* <Route path="/proposals/new" element={<ProposalPage/>}/> */}
<Route path="/forms" element={<FormsPage/>}/>
<Route path="/forms/:id" element={<FormPage/>}/>
<Route path="/degrees" element={<DegreesPage/>}/>
<Route path="/degrees/:id" element={<DegreePage/>}/>
<Route path="/curricula" element={<CurriculaPage/>}/>
<Route path="/curricula/:id" element={<CurriculumPage/>}/>
<Route path="/form_templates/:id" element={<FormTemplatePage/>}/>
<Route path="/form_templates" element={<FormTemplatesPage/>}/>
<Route path="/form_templates/edit/:id" element={<EditFormTemplatePage/>}/>
<Route path="/form_templates/edit" element={<AddFormTemplatePage/>} />
<Route path="/exams/edit/:id" element={<EditExamPage/>}/>
<Route path="/exams/:id" element={<ExamPage/>}/>
<Route path="/exams" element={<ExamsPage/>}/>
<Route path="/users" element={<UsersPage/>}/>
<Route path="/users/:id" element={<UserPage/>}/>
<Route path="/settings" element={<SettingsPage/>}/>
</Routes>
</div>
<Footer/>
</div>
<Routes>
Routes
<Route path="/proposals/:id/pdf" element={<ProposalPagePdf/>}/>
<Route path="*" element={<PageWithNavBar />}>
</Route>
</Routes>
</BrowserRouter>
</div>
</EngineProvider>
Expand All @@ -111,3 +84,43 @@ function SinglePageInternal({config}) {
function Splash(props) {
return <p>Splash!</p>
}

function PageWithNavBar(props) {
const engine = useEngine()
const modalConfirmData = engine.state.modalConfirmData
return <>
<NavBar/>
<div id="content-wrapper" className="d-flex flex-column">
<TopBar/>
<Modal title={ modalConfirmData.title } content={ modalConfirmData.content } callback={ modalConfirmData.callback }></Modal>
<Flash messages={ engine.state.flashMessages } onClick={ () => engine.hideFlash() }></Flash>
<div id="content" className="px-4">
<Routes>
<Route path="/" element={<Splash/>}/>
<Route path="/index.html" element={<Splash/>}/>
<Route path="/proposals/edit/:id" element={<EditProposalPage/>}/>
<Route path="/proposals/:id" element={<ProposalPage/>}/>
<Route path="/proposals" element={<ProposalsPage/>}/>
{/* <Route path="/proposals/new" element={<ProposalPage/>}/> */}
<Route path="/forms" element={<FormsPage/>}/>
<Route path="/forms/:id" element={<FormPage/>}/>
<Route path="/degrees" element={<DegreesPage/>}/>
<Route path="/degrees/:id" element={<DegreePage/>}/>
<Route path="/curricula" element={<CurriculaPage/>}/>
<Route path="/curricula/:id" element={<CurriculumPage/>}/>
<Route path="/form_templates/:id" element={<FormTemplatePage/>}/>
<Route path="/form_templates" element={<FormTemplatesPage/>}/>
<Route path="/form_templates/edit/:id" element={<EditFormTemplatePage/>}/>
<Route path="/form_templates/edit" element={<AddFormTemplatePage/>} />
<Route path="/exams/edit/:id" element={<EditExamPage/>}/>
<Route path="/exams/:id" element={<ExamPage/>}/>
<Route path="/exams" element={<ExamsPage/>}/>
<Route path="/users" element={<UsersPage/>}/>
<Route path="/users/:id" element={<UserPage/>}/>
<Route path="/settings" element={<SettingsPage/>}/>
</Routes>
</div>
<Footer/>
</div>
</>
}

0 comments on commit b11da27

Please sign in to comment.