Skip to content

Commit

Permalink
aggiunta view personalizzata per corsi di dottorato ed altre lievi mo…
Browse files Browse the repository at this point in the history
…difiche
  • Loading branch information
aziis98 committed Sep 30, 2023
1 parent 9a28cf0 commit bca1e7c
Show file tree
Hide file tree
Showing 7 changed files with 554 additions and 149 deletions.
24 changes: 22 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"passport-oauth2": "^1.6.1",
"react": "^18.2.0",
"react-bootstrap": "^2.5.0",
"react-bootstrap-icons": "^1.10.3",
"react-bootstrap-typeahead": "^6.0.0",
"react-csv": "^2.2.2",
"react-datepicker": "^4.8.0",
Expand Down
4 changes: 2 additions & 2 deletions server/models/Event.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const EventColloquium = model('EventColloquium', eventColloquiumSchema)
// Corso di Dottorato
//

const lectureDateSchema = new Schema({
const lessonSchema = new Schema({
date: { type: Date, label: 'data e orario', required: true },
duration: { type: Number, label: 'durata (in minuti)', default: 120, required: true },
room: { type: ObjectId, label: 'aula', ref: 'Room', required: true },
Expand All @@ -82,7 +82,7 @@ const lectureDateSchema = new Schema({
const eventPhdCourseSchema = new Schema({
title: {type: String, label: 'titolo'},
lecturer: { type: ObjectId, label: 'lecturer', ref: 'Person', required: true },
lectureDates: [lectureDateSchema],
lessons: [lessonSchema],

createdBy,
updatedBy,
Expand Down
108 changes: 108 additions & 0 deletions src/components/PhdCourseLessonList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Button, Table } from 'react-bootstrap'

import * as Icon from 'react-bootstrap-icons'
import { Link } from 'react-router-dom';
import { useEngine } from '../Engine';
import Loading from './Loading';

/** @typedef {import('../models/EventPhdCourse').Lesson} Lesson */

/**
* Formats a UTC date to "YYYY-MM-DD HH:mm"
* @type {(date: string | Date) => string}
*/
const formatDate = (date) => {
if (typeof date === 'string') date = new Date(date)

const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');

const formattedDate = `${year}-${month}-${day} ${hours}:${minutes}`;

return formattedDate;
}

export const isValidDate = (dateString) => {
try {
parseDate(dateString)
return true
} catch (e) {
return false
}
}

export const parseDate = (dateString) => {
const [datePart, timePart] = dateString.trim().split(/\s+/g)
const [year, month, day] = datePart.split('-')
const [hours, minutes] = timePart.split(':')

console.log(year, month, day, hours, minutes)

if (year === undefined || month === undefined || day === undefined || hours === undefined || minutes === undefined) {
throw new Error('invalid date format, expected "YYYY-MM-DD HH:mm"')
}

const utcDate = new Date(
parseInt(year, 10),
parseInt(month, 10) - 1, // Months are zero-based
parseInt(day, 10),
parseInt(hours, 10),
parseInt(minutes, 10)
)

return utcDate
}

/**
* @param {{ lessons: Lesson[], deleteLesson: (index: number) => void }} props
*/
export const LessonTable = ({ lessons, deleteLesson }) => {
const isEdit = !!deleteLesson

const Room = ({ id }) => {
const engine = useEngine()
const { isSuccess, data } = engine.useGet('room', id)

if (!isSuccess) return <Loading />
const { Room } = engine.Models
return <Link key={data._id} to={Room.viewUrl(data._id)}>{Room.describe(data)}</Link>
}

return (
<Table className="align-middle">
<thead className="thead-dark">
<tr>
<th>Orario</th>
<th>Durata (minuti)</th>
<th>Stanza</th>
{isEdit && <th></th>}
</tr>
</thead>
<tbody>
{lessons.map((lesson, i) => (
<tr key={i}>
<td>{formatDate(lesson.date)}</td>
<td>{lesson.duration}</td>
<td>
{typeof lesson.room !== 'string'
? lesson.room.code
: <Room id={lesson.room} />}
</td>
{isEdit && (
<td>
<Button
className="btn btn-danger btn-sm"
onClick={() => deleteLesson(i)}>
<Icon.Trash />
</Button>
</td>
)}
</tr>
))}
</tbody>
</Table>
)
}
157 changes: 12 additions & 145 deletions src/models/EventPhdCourse.js
Original file line number Diff line number Diff line change
@@ -1,150 +1,17 @@
import { useEffect, useState } from 'react'
import { Route, useParams, Navigate } from 'react-router-dom'
import { Route } from 'react-router-dom'
import { Link } from 'react-router-dom'
import { Button, ButtonGroup, Card, Container, Form } from 'react-bootstrap'

import ModelsPage from '../pages/ModelsPage'
import ModelViewPage from '../pages/ModelViewPage'
import PhdCourseEditPage from '../pages/PhdCourseEditPage'
import PhdCourseViewPage from '../pages/PhdCourseViewPage'


import Loading from '../components/Loading'
import { useEngine } from '../Engine'
import { ModelHeading } from '../components/ModelHeading'
import { PersonInput, StringInput } from '../components/Input'

const compareValue = (v1, v2) => {
// capita di confrontare una stringa con una data
if (JSON.stringify(v1) === JSON.stringify(v2)) return true
if (typeof(v1) !== typeof(v2)) return false
if (Array.isArray(v1)) {
if (v1.length !== v2.length) return false
return v1.every((v, i) => compareValue(v, v2[i]))
}
if (typeof(v1) === 'object') return (v1?._id && v1?._id === v2?._id)
return v1 === v2
}

const EditPage = ({ Model }) => {
const params = useParams()
const id = params.id

// const [searchParams] = useSearchParams()
// const clone_id = searchParams.get('clone')

const [ redirect ] = useState(null)

const create = id === 'new'
const [modifiedObj, setModifiedObj] = useState(null)
const engine = useEngine()
// const putObj = engine.usePut(objCode)
// const patchObj = engine.usePatch(objCode)
// const engineDeleteObj = engine.useDelete(objCode)

const { status, data } = engine.useGet(Model.code, id)

useEffect(() => {
if (status === "success") {
setModifiedObj(data)
}
}, [status, data])

if (redirect !== null) return <Navigate to={redirect} />

if (status === "error") return <div>errore caricamento</div>
if (status === "loading") return <Loading />
if (modifiedObj === null) return <Loading />

const originalObj = data
const modifiedFields = Object.keys(modifiedObj)
.filter(key => !compareValue(modifiedObj[key], originalObj[key]))
const changed = modifiedFields.length > 0

// const TitleField = withProps(modifiedObj, setModifiedObj, StringInput, 'title')
// const LecturerField = withProps(modifiedObj, setModifiedObj, PersonInput, 'lecturer')

return (
<>
<ModelHeading model={Model}/>
<Card>
<Card.Header>
<h3>
{create
? "Nuovo Corso di Dottorato"
: `Modifica Corso di Dottorato ${Model.describe(modifiedObj)}`}
</h3>
</Card.Header>
<Card.Body>
<Form onSubmit={e => e.preventDefault()}>
<Form.Group className="row my-2">
<Form.Label className="col-sm-2" htmlFor={"title"} style={{textAlign: "right"}}>
Titolo
</Form.Label>
<div className="col-sm-10">
<StringInput
id="title"
value={modifiedObj.title}
setValue={value => {
setModifiedObj(obj => ({
...obj,
title: value,
}))
}}
/>
</div>
<div className="col-sm-2"></div>
</Form.Group>
<Form.Group className="row my-2">
<Form.Label className="col-sm-2" htmlFor={"lecturer"} style={{textAlign: "right"}}>
Docente
</Form.Label>
<div className="col-sm-10">
<PersonInput
id="lecturer"
value={modifiedObj.lecturer}
setValue={value => {
setModifiedObj(obj => ({
...obj,
lecturer: value,
}))
}}
/>
</div>
<div className="col-sm-2"></div>
</Form.Group>
<Form.Group className="row my-2">
<Form.Label className="col-sm-2" htmlFor={"lecturer"} style={{textAlign: "right"}}>
Lezioni
</Form.Label>
<div className="col-sm-10">
<Button className="offset-sm-10 col-sm-2 btn-primary">
Nuova Lezione
</Button>
<Container>
Tabella degli orari...
</Container>
</div>
</Form.Group>
<ButtonGroup className="mt-3">
<Button
className="btn-primary"
disabled= { !changed }>
{create ? "Aggiungi Corso di Dottorato" : "Salva Modifiche"}
</Button>
<Button className="btn btn-secondary">
Annulla Modifiche
</Button>
{!create && (
<Button className="btn btn-danger pull-right">
Elimina {Model.describe(modifiedObj)}
</Button>
)}
</ButtonGroup>
</Form>
</Card.Body>
</Card>
</>
)
}
/**
* @typedef {{
* date: Date,
* duration: number,
* room: Room
* }} Lesson
*/

export default class EventPhdCourse {
constructor() {
Expand All @@ -169,8 +36,8 @@ export default class EventPhdCourse {
this.schema = null

this.IndexPage = ModelsPage
this.ViewPage = ModelViewPage
this.EditPage = EditPage
this.ViewPage = PhdCourseViewPage
this.EditPage = PhdCourseEditPage
}

// absolute url of objects index
Expand Down
Loading

0 comments on commit bca1e7c

Please sign in to comment.