diff --git a/client/components/projects/content.tsx b/client/components/projects/content.tsx index fcf2dbc..54aeab0 100644 --- a/client/components/projects/content.tsx +++ b/client/components/projects/content.tsx @@ -3,8 +3,10 @@ import { useEffect, useRef } from 'react'; import { Person, ProjectModel } from '@/helpers/types'; import ProjectCard from './project-card.mjs'; -import ProjectComponent from './project-component.mjs'; import Modal from './project-modal.mjs'; +import './project-component.js'; +import './project-modal.js'; +import './project-card.js'; interface ContentProps { projects: ProjectModel[]; @@ -14,26 +16,12 @@ interface ContentProps { export default function Content({ projects, user }: ContentProps) { const projectComponentRef = useRef(null); - useEffect(() => { - // Registra i web components - if (!customElements.get('project-card')) { - customElements.define('project-card', ProjectCard); - } - if (!customElements.get('project-component')) { - customElements.define('project-component', ProjectComponent); - } - if (!customElements.get('modal-component')) { - customElements.define('modal-component', Modal); - } - - - }, []); - useEffect(() => { // Passa i progetti al custom element quando disponibile if (projectComponentRef.current) { projectComponentRef.current.projects = projects; projectComponentRef.current._user = user; + // projectComponentRef.classList.add('font-sans', 'bg-gray-900', 'text-white'); } }, [projects, user]); diff --git a/client/components/projects/project-card.mjs b/client/components/projects/project-card.js similarity index 57% rename from client/components/projects/project-card.mjs rename to client/components/projects/project-card.js index 40ef7b4..3e33572 100644 --- a/client/components/projects/project-card.mjs +++ b/client/components/projects/project-card.js @@ -7,187 +7,225 @@ class ProjectCard extends HTMLElement { this.user = null; this.project = null; - const style = document.createElement('style'); - style.textContent = ` - :host { - --bg-color: #f5f5f5; - --text-color: #333; - --gantt-bg-color: white; - --cell-bg-color: #e0e0e0; - --hover-bg-color: #F0F8FF; - --pending-color: silver; - --partial-completed-color: #F4A460; - --title-color: #333; - --success-color: #4CAF50; - } + this.setupStyle(); + shadow.appendChild(wrapper); - :host([dark-mode]) { - --bg-color: #333; - --text-color: #f5f5f5; - --gantt-bg-color: #444; - --cell-bg-color: #666; - --hover-bg-color: #555; + this._modal = null; } - .project-card { - font-family: Arial, sans-serif; - padding: 20px; - background-color: var(--bg-color); - border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - } - - h2, h3{ - margin-top: 0; - color: var(--text-color); - } - - .gantt-chart { - overflow-x: auto; - margin-top: 20px; - background-color: var(--gantt-bg-color); - border-radius: 4px; - padding: 10px; - } - - .gantt-cell { - flex: 1; - min-width: 40px; - height: 30px; - border-right: 1px solid var(--cell-bg-color); - text-align: center; - font-size: 12px; - color: var(--text-color); - display: flex; - align-items: center; - justify-content: center; - } + setupStyle() { + this.shadowRoot.innerHTML = ` + + `; } connectedCallback() { @@ -205,8 +243,11 @@ class ProjectCard extends HTMLElement { const days = this.getDaysBetween(startDate, endDate); wrapper.innerHTML = ` -

${this.project.title}

-

${this.project.description}

+
+

${this.project.title}

+ +
+

${this.project.description}

${this.renderGanttChart(this.project.activities, days, startDate)} @@ -247,7 +288,6 @@ class ProjectCard extends HTMLElement { throw new Error('Error updating activity'); }).then((data) => { this.modifyProject(data.project); - console.log(data.message); }).catch((error) => { console.error(error); }); @@ -261,28 +301,39 @@ class ProjectCard extends HTMLElement { const deleteProjectBtn = this.shadowRoot.querySelector("#delete-proj"); const deleteActivityBtn = form.querySelector('#delete-activity'); -// Event delegation for task name and completion toggle - const ganttChart = this.shadowRoot.querySelector('.gantt-chart'); - ganttChart.addEventListener('click', (event) => { - const taskNameCell = event.target.closest('.task-name'); - const taskCell = event.target.closest('.gantt-task-cell'); - - if (taskNameCell) { - const taskId = taskNameCell.getAttribute('data-activity-id'); - if (taskId) { - this.openModal(taskId, project, false); - } - } else if (taskCell) { - const row = taskCell.closest('.gantt-row'); - if (row) { - const taskNameCell = row.querySelector('.task-name'); - const taskId = taskNameCell?.getAttribute('data-activity-id'); - if (taskId) { - this.toggleActivityCompletion(taskId, project); - } + const ganttCells = this.shadowRoot.querySelectorAll('.gantt-task-cell'); + ganttCells.forEach(cell => { + cell.addEventListener('click', (e) => { + const activityId = cell.parentElement.dataset.activityId; + this.toggleActivityCompletion(activityId, project); + }); + cell.addEventListener('mouseover', (e) => { + // make background color lighter + e.target.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; + e.target.style.cursor = 'pointer'; + }); + cell.addEventListener('mouseout', (e) => { + e.target.style.backgroundColor = ''; + }); + }); + + const editButtons = this.shadowRoot.querySelectorAll('.edit-button'); + editButtons.forEach(button => { + button.addEventListener('click', (e) => { + e.stopPropagation(); // Previene il bubbling dell'evento + const activityId = button.closest('.gantt-row').dataset.activityId; + this.openModal(activityId, project, false); + }); + }); + + const infoCells = this.shadowRoot.querySelectorAll('.task-info'); + infoCells.forEach(cell => { + cell.addEventListener('click', (e) => { + const activityId = cell.parentElement.dataset.activityId; + this.openModal(activityId, project, false); } - } - }); + ); + }); addActivityBtn.addEventListener('click', () => { this.openModal(null, project, true); @@ -311,6 +362,8 @@ class ProjectCard extends HTMLElement { form.addEventListener('submit', (e) => this.handleFormSubmit(e, project)); + + this.setupTooltips(); } addError(message) { @@ -527,24 +580,52 @@ class ProjectCard extends HTMLElement { } renderGanttChart(activities, days, startDate) { - const header = this.renderGanttHeader(days); - const rows = activities && activities.length > 0 ? activities.map(activity => this.renderGanttRow(activity, days, startDate)).join('') : '
No activities found
'; + const rowsHtml = activities.map(activity => this.renderGanttRow(activity, days, startDate)); + const fixedGanttRows = rowsHtml.map( + (row) => { + return row.rowHtml.fixedHtml + + row?.subActivitiesHtml?.map(subActivity => subActivity.rowHtml.fixedHtml).join(''); + }).join(''); + const overlayGanttRows = rowsHtml.map( + (row) => { + return row.rowHtml.overlayHtml + + row?.subActivitiesHtml?.map(subActivity => subActivity.rowHtml.overlayHtml).join(''); + }).join(''); + return ` -
${header}
- ${rows} +
+
+ ${this.renderFixedGanttHeader()} +
+ ${fixedGanttRows} +
+
+
+ ${this.renderOverlayGanttHeader(days)} +
+ ${overlayGanttRows} +
`; } - renderGanttHeader(days) { + renderFixedGanttHeader() { + return ` +
Task
+ + `; + } + + renderOverlayGanttHeader(days) { return ` -

Task

-
Days
-
Start Date
-
End Date
-
Participants
+
Days
+
Start Date
+
End Date
+
Participants
${days.map(day => `
${day.getDate()}/${day.getMonth() + 1}
`).join('')} `; } + + isActivityFullyComplete(activity) { if (!activity.subActivities || activity.subActivities.length === 0) { return activity.completed; @@ -602,39 +683,84 @@ class ProjectCard extends HTMLElement { const duration = this.getDaysBetween(activityStart, activityEnd).length; const completionStatus = this.getActivityCompletionStatus(activity, parentActivity); - const rowHtml = ` -
-
- ${level === 1 ? '' : ''} ${activity.name} -
-
${duration}
-
${this.formatDate(activityStart)}
-
${this.formatDate(activityEnd)}
-
- ${activity.participants?.length > 0 ? activity.participants.join(', ') : 'no one'} + const rowHtml = { + fixedHtml: ` +
+
+ + ${level === 1 ? '' : ''} ${activity.name} +
- ${days.map(day => { - const dayTimestamp = day.getTime(); - const activityStartTimestamp = activityStart.getTime(); - const activityEndTimestamp = activityEnd.getTime(); + `, + overlayHtml: ` +
+
${duration}
+
${this.formatDate(activityStart)}
+
${this.formatDate(activityEnd)}
+
+ ${activity.participants?.length > 0 ? activity.participants.join(', ') : 'no one'} +
- if (dayTimestamp >= activityStartTimestamp && dayTimestamp <= activityEndTimestamp) { - return `
`; - } - return '
'; - }).join('')} -
- `; + ${days.map(day => { + const dayTimestamp = day.getTime(); + const activityStartTimestamp = activityStart.getTime(); + const activityEndTimestamp = activityEnd.getTime(); + + if (dayTimestamp >= activityStartTimestamp && dayTimestamp <= activityEndTimestamp) { + const statusText = completionStatus === 'completed' ? 'Completed' : + completionStatus === 'partial-completed' ? 'Partially Completed' : + completionStatus === 'pending' ? 'In Progress' : 'Not Started'; + return `
`; + } + return '
'; + }).join('') + } +
+ `}; const subActivitiesHtml = activity.subActivities - ? activity.subActivities - .map(subActivity => this.renderGanttRow(subActivity, days, startDate, level + 1, activity)) - .join('') - : ''; + ? activity.subActivities.map(subActivity => this.renderGanttRow(subActivity, days, startDate, level + 1, activity)) + : []; - return rowHtml + subActivitiesHtml; + return { rowHtml, subActivitiesHtml }; } + setupTooltips() { + const tooltip = document.createElement('div'); + tooltip.className = 'tooltip'; + this.shadowRoot.appendChild(tooltip); + + const taskCells = this.shadowRoot.querySelectorAll('.gantt-task-cell'); + + taskCells.forEach(cell => { + cell.addEventListener('mouseover', (e) => { + const activityName = cell.dataset.activityName; + const status = cell.dataset.status; + tooltip.textContent = `${activityName}: ${status}`; + + // Posiziona il tooltip + // using the mouse coordinates + const cords = cell.getBoundingClientRect(); + const sideBarOff = window.innerWidth > 768 ? 200 : 0; + const x = cords.left + window.scrollX - sideBarOff; + const y = cords.top + window.scrollY; + tooltip.style.left = `${x + 10}px`; + tooltip.style.top = `${y + 20}px`; + + tooltip.classList.add('visible'); + }); + + cell.addEventListener('mouseout', () => { + tooltip.classList.remove('visible'); + }); + }); + } getDaysBetween(start, end) { const days = []; @@ -651,4 +777,4 @@ class ProjectCard extends HTMLElement { } } -export default ProjectCard; +customElements.define('project-card', ProjectCard); diff --git a/client/components/projects/project-component.mjs b/client/components/projects/project-component.js similarity index 69% rename from client/components/projects/project-component.mjs rename to client/components/projects/project-component.js index 539a907..952aab3 100644 --- a/client/components/projects/project-component.mjs +++ b/client/components/projects/project-component.js @@ -1,3 +1,4 @@ +// project-component.js class ProjectComponent extends HTMLElement { constructor() { super(); @@ -20,56 +21,88 @@ class ProjectComponent extends HTMLElement { }); } + // Inject Tailwind styles into shadow DOM setupStyle() { - const style = document.createElement('style'); - style.textContent = ` - :host { - display: block; - font-family: Arial, sans-serif; - } - .navigation { - display: flex; - justify-content: center; - margin-top: 20px; - } - .navigation button { - padding: 8px 16px; - margin: 0 5px; - cursor: pointer; - background-color: #4CAF50; - color: white; - border: none; - border-radius: 4px; - font-size: 14px; - margin-left: 10px; - } - .navigation button:disabled { - background-color: #ccc; - cursor: not-allowed; - } -#projectForm input, #projectForm textarea { - width: 100%; - padding: 8px; - margin: 8px 0; - box-sizing: border-box; - } + this.shadowRoot.innerHTML = ` + `; - - this.shadowRoot.appendChild(style); } + handleDeleteProject(event) { const projectId = event.detail.projectId; @@ -102,7 +135,6 @@ class ProjectComponent extends HTMLElement { connectedCallback() { this.setupStyle(); - this.render(); } set projects(value) { @@ -149,8 +181,8 @@ class ProjectComponent extends HTMLElement { return { title, - startDate:new Date(startDate), - deadline:new Date(deadline), + startDate: new Date(startDate), + deadline: new Date(deadline), description, activities: [], members @@ -162,7 +194,7 @@ class ProjectComponent extends HTMLElement { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({project:newProject}) + body: JSON.stringify({ project: newProject }) }).then((res) => { if (res.ok) { return res.json(); @@ -177,23 +209,24 @@ class ProjectComponent extends HTMLElement { }; render() { - // Save the style element - const style = this.shadowRoot.querySelector('style'); - // Clear the shadow DOM this.shadowRoot.innerHTML = ''; - // Re-add the style element - if (style) { - this.shadowRoot.appendChild(style); - } - - if (this._projects.length === 0) return; + this.setupStyle(); - const projectCard = document.createElement('project-card'); - projectCard.setAttribute('project', JSON.stringify(this._projects[this.currentIndex])); - projectCard.setAttribute('user', JSON.stringify(this._user)); - this.shadowRoot.appendChild(projectCard); + if (this._projects.length > 0) { + const projectCard = document.createElement('project-card'); + projectCard.setAttribute('project', JSON.stringify(this._projects[this.currentIndex])); + projectCard.setAttribute('user', JSON.stringify(this._user)); + this.shadowRoot.appendChild(projectCard); + } else { + const noProjdiv = document.createElement('div'); + noProjdiv.className = 'no-projects'; + this.shadowRoot.appendChild(noProjdiv); + const noProjects = document.createElement('p'); + noProjects.textContent = 'No projects found'; + noProjdiv.appendChild(noProjects); + } const modal = document.createElement('modal-component'); @@ -255,5 +288,4 @@ class ProjectComponent extends HTMLElement { } } - -export default ProjectComponent; +customElements.define('project-component', ProjectComponent); diff --git a/client/components/projects/project-modal.mjs b/client/components/projects/project-modal.js similarity index 56% rename from client/components/projects/project-modal.mjs rename to client/components/projects/project-modal.js index a18be54..3c6dd09 100644 --- a/client/components/projects/project-modal.mjs +++ b/client/components/projects/project-modal.js @@ -22,64 +22,81 @@ class Modal extends HTMLElement { } } + setupStyle() { + this.shadowRoot.innerHTML = ` + +`; + } + setupModal() { - const style = document.createElement('style'); - style.textContent = ` - .modal { - display: none; - position: fixed; - z-index: 1; - left: 0; - top: 0; - border-radius: 15px; - width: 100%; - height: 100%; - overflow: auto; - background-color: rgba(0,0,0,0.4); - } - .modal-content { - background-color: #fefefe; - margin: 15% auto; - padding: 20px; - border: 1px solid #888; - width: 80%; - max-width: 500px; - border-radius: 15px; - } - .close { - color: #aaa; - float: right; - font-size: 28px; - font-weight: bold; - cursor: pointer; - } - .close:hover, - .close:focus { - color: black; - text-decoration: none; - cursor: pointer; - } - .text-error { - color: red; - } - h2 { - color: #333; - } - `; + this.setupStyle(); const modal = document.createElement('div'); modal.classList.add('modal'); modal.innerHTML = ` `; this.shadowRoot.appendChild(modal); - this.shadowRoot.appendChild(style); this.modal = this.shadowRoot.querySelector('.modal'); this.closeBtn = this.shadowRoot.querySelector('.close'); @@ -92,11 +109,11 @@ class Modal extends HTMLElement { }); } - setTitle(t){ + setTitle(t) { this.shadowRoot.getElementById('modalTitle').textContent = t; } - setError(e){ + setError(e) { this.shadowRoot.getElementById('modalError').textContent = e; } @@ -120,7 +137,7 @@ class Modal extends HTMLElement { } } - handleSave(){ + handleSave() { if (this.onsave) { // Dispatch custom event that parent can listen to this.dispatchEvent(new CustomEvent('modalSave', { @@ -135,4 +152,5 @@ class Modal extends HTMLElement { } } -export default Modal; +customElements.define('modal-component', Modal); + diff --git a/client/helpers/custom-types.d.ts b/client/helpers/custom-types.d.ts index 1075d5c..9eabede 100644 --- a/client/helpers/custom-types.d.ts +++ b/client/helpers/custom-types.d.ts @@ -12,7 +12,12 @@ declare global { 'project-component': React.DetailedHTMLProps, HTMLElement> & { projects?: ProjectModel[]; }; + 'project-card': React.DetailedHTMLProps, HTMLElement> & { + project: ProjectModel; + }; + 'modal-component': React.DetailedHTMLProps, HTMLElement>; } + } } diff --git a/client/package-lock.json b/client/package-lock.json index dffa3ae..1ebb287 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -49,11 +49,11 @@ "@types/node": "18.7.18", "@types/react": "18.0.20", "@types/react-dom": "18.0.6", - "autoprefixer": "^10.4.15", + "autoprefixer": "^10.4.20", "eslint": "8.23.1", "eslint-config-next": "13.4.16", - "postcss": "^8.4.28", - "tailwindcss": "^3.3.3", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.14", "typescript": "4.8.3" } }, @@ -11157,9 +11157,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.12.tgz", - "integrity": "sha512-Htf/gHj2+soPb9UayUNci/Ja3d8pTmu9ONTfh4QY8r3MATTZOzmv6UYWF7ZwikEIC8okpfqmGqrmDehua8mF8w==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", diff --git a/client/package.json b/client/package.json index aaf1dce..ab1d5f7 100644 --- a/client/package.json +++ b/client/package.json @@ -6,7 +6,8 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "build-css": "npx tailwindcss -i styles/project.css -o public/styles/project.css --minify; npx tailwind -i styles/modal.css -o public/styles/modal.css; npx tailwind -i styles/gantt.css -o public/styles/gantt.css" }, "dependencies": { "@emotion/react": "^11.13.3", @@ -50,11 +51,11 @@ "@types/node": "18.7.18", "@types/react": "18.0.20", "@types/react-dom": "18.0.6", - "autoprefixer": "^10.4.15", + "autoprefixer": "^10.4.20", "eslint": "8.23.1", "eslint-config-next": "13.4.16", - "postcss": "^8.4.28", - "tailwindcss": "^3.3.3", + "postcss": "^8.4.47", + "tailwindcss": "^3.4.14", "typescript": "4.8.3" } } diff --git a/client/styles/gantt.css b/client/styles/gantt.css new file mode 100644 index 0000000..65e9cb5 --- /dev/null +++ b/client/styles/gantt.css @@ -0,0 +1,121 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +.project-card { + /*@apply font-sans p-5 bg-background rounded-lg shadow-lg;*/ + @apply font-sans p-5 rounded-lg shadow-xl bg-secondary-100; + /* change bg-background to default in dark mode */ +} + +.project-card .title { + @apply mt-0 text-secondary font-semibold text-2xl; +} + +.gantt-chart { + @apply overflow-x-auto mt-5 bg-[var(--gantt-bg-color)] rounded-md p-2.5; +} + +.gantt-cell { + @apply flex-1 min-w-[40px] h-[30px] border-r text-center text-xs text-[var(--text-color)] flex items-center justify-center p-0 border-r-1 border-default-400; + margin: 0 !important; +} + +.gantt-task-cell:hover { + @apply bg-[var(--hover-bg-color)]; +} + +.title { + @apply text-[var(--title-color)]; +} + +.gantt-header, +.gantt-row { + @apply flex space-x-2; +} + +.gantt-header { + @apply font-bold; +} + +.gantt-cell:last-child { + @apply border-r-0; +} + +.gantt-task { + @apply bg-green-600 h-[20px] rounded-md; +} + +.gantt-task-cell.completed { + @apply bg-success; +} + +.gantt-task-cell.partial-completed { + @apply bg-warning; +} + +.gantt-task-cell.pending { + @apply bg-primary-800; +} + +.gantt-task-cell.passed { + @apply bg-yellow-500; +} + +.gantt-task-cell.child-completed { + @apply bg-success; +} + +.task-info { + @apply min-w-[200px] max-w-[200px] pr-2.5 justify-start; +} + +.task-info:hover { + @apply cursor-pointer text-blue-600; +} + +.subactivity { + @apply ml-5; +} + +.days-column { + @apply min-w-[50px] max-w-[50px]; +} + +.start-date-column, +.end-date-column { + @apply min-w-[80px] max-w-[80px]; +} + +.participants-column { + @apply min-w-[150px] max-w-[150px] overflow-hidden; +} + +.success { + @apply bg-green-600; +} + +.add-activity-btn { + @apply bg-success text-white p-2 border-none cursor-pointer mt-2.5 rounded-md; +} + +.parent-activity-select { + @apply w-full p-2 my-2 box-border; +} + +.delete { + @apply bg-red-600 text-white py-1.5 px-2.5 border-none cursor-pointer rounded-md float-right; +} + +#activityForm input, +#activityForm textarea { + @apply w-full p-2 my-2 box-border rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary; +} + +#activityForm button { + @apply text-white py-2.5 px-4 border-none cursor-pointer mt-2.5 rounded-md; +} + +.header-inline { + @apply flex items-center justify-between; +} diff --git a/client/styles/modal.css b/client/styles/modal.css new file mode 100644 index 0000000..fadf7d4 --- /dev/null +++ b/client/styles/modal.css @@ -0,0 +1,27 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +.modal { + @apply fixed inset-0 z-10 bg-black bg-opacity-40 flex items-center justify-center hidden overflow-auto; +} + +.modal-content { + @apply bg-default rounded-lg p-5 w-4/5 max-w-lg mx-auto my-20; +} + +.modal-header { + @apply text-xl font-semibold mb-4; +} + +.modal .close { + @apply text-gray-400 text-2xl font-bold float-right cursor-pointer hover:text-black; +} + +.modal .error-message { + @apply text-red-500 text-sm mt-2; +} + +.modal h2 { + @apply text-2xl text-center font-semibold; +} diff --git a/client/styles/project.css b/client/styles/project.css new file mode 100644 index 0000000..fde32b6 --- /dev/null +++ b/client/styles/project.css @@ -0,0 +1,33 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:host { + @apply block font-sans; +} + +.navigation { + @apply flex justify-center mt-5; +} + +.navigation button { + @apply px-4 py-2 mx-1 cursor-pointer bg-secondary text-white border-none rounded-md text-sm ml-2.5 hover:bg-primary-600 disabled:bg-gray-300 disabled:cursor-not-allowed; +} + +#newProject { + @apply bg-primary; +} + +#projectForm input, +#projectForm textarea { + @apply w-full p-2 my-2 box-border rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-primary; +} + +#projectForm button { + @apply text-white py-2.5 px-4 border-none cursor-pointer mt-2.5 rounded-md; +} + +.success { + @apply bg-success hover:bg-success-600; +} + diff --git a/client/tailwind.config.js b/client/tailwind.config.js index 67430f9..2e43844 100644 --- a/client/tailwind.config.js +++ b/client/tailwind.config.js @@ -6,13 +6,16 @@ module.exports = { "./app/**/*.{js,ts,jsx,tsx,mdx}", "./pages/**/*.{js,ts,jsx,tsx,mdx}", "./components/**/*.{js,ts,jsx,tsx,mdx}", + "./components/**/*.{js,ts,jsx,tsx,mdx,mjs}", - // Or if using `src` directory: - "./src/**/*.{js,ts,jsx,tsx,mdx}", "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}", ], theme: { - extend: {}, + extend: { + boxShadow: { + 'light': '0 4px 6px rgba(255, 255, 255, 0.1)', // Ombra chiara per dark mode + } + }, }, darkMode: "class", plugins: [nextui(), require("@tailwindcss/typography")], diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index b34708e..0000000 --- a/package-lock.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "name": "proj-tw202425", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@types/leaflet": "^1.9.13", - "leaflet": "^1.9.4", - "leaflet-defaulticon-compatibility": "^0.1.2", - "react-leaflet": "^4.2.1", - "use-debounce": "^10.0.4" - } - }, - "node_modules/@react-leaflet/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", - "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", - "license": "Hippocratic-2.1", - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", - "license": "MIT" - }, - "node_modules/@types/leaflet": { - "version": "1.9.13", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.13.tgz", - "integrity": "sha512-wwLL4VKKwYlLmhMQRc/8HT5/8HgkzZyETG0hG3nbsSiHKSdxBWZnHqEkRIOOtpyUks3gbc81dk9WgQMC6bicDw==", - "license": "MIT", - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT", - "peer": true - }, - "node_modules/leaflet": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", - "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", - "license": "BSD-2-Clause" - }, - "node_modules/leaflet-defaulticon-compatibility": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/leaflet-defaulticon-compatibility/-/leaflet-defaulticon-compatibility-0.1.2.tgz", - "integrity": "sha512-IrKagWxkTwzxUkFIumy/Zmo3ksjuAu3zEadtOuJcKzuXaD76Gwvg2Z1mLyx7y52ykOzM8rAH5ChBs4DnfdGa6Q==", - "license": "BSD-2-Clause" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-leaflet": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", - "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", - "license": "Hippocratic-2.1", - "dependencies": { - "@react-leaflet/core": "^2.1.0" - }, - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/use-debounce": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.4.tgz", - "integrity": "sha512-6Cf7Yr7Wk7Kdv77nnJMf6de4HuDE4dTxKij+RqE9rufDsI6zsbjyAxcH5y2ueJCQAnfgKbzXbZHYlkFwmBlWkw==", - "license": "MIT", - "engines": { - "node": ">= 16.0.0" - }, - "peerDependencies": { - "react": "*" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index d8a06fb..0000000 --- a/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "dependencies": { - "@types/leaflet": "^1.9.13", - "leaflet": "^1.9.4", - "leaflet-defaulticon-compatibility": "^0.1.2", - "react-leaflet": "^4.2.1", - "use-debounce": "^10.0.4" - } -} diff --git a/server/src/routes/projects.js b/server/src/routes/projects.js index 16c93f3..9f8146d 100644 --- a/server/src/routes/projects.js +++ b/server/src/routes/projects.js @@ -27,8 +27,6 @@ export function createProjectRouter(db) { return res.status(400).json({ message: e.message }); } - if (!result || result.length == 0) return res.status(404).json({ message: "Nessun progetto trovato" }); - return res.status(200).json(result); }); diff --git a/server/src/services/projects.mjs b/server/src/services/projects.mjs index 624bfd7..1c80eba 100644 --- a/server/src/services/projects.mjs +++ b/server/src/services/projects.mjs @@ -82,7 +82,7 @@ export default function createProjectService(models, lib) { async getProjects(uid) { let projects = await projectModel.find({ $or: [{ creator: uid }, { members: uid }] }); - if (!projects || projects.length === 0) throw new Error("Nessun progetto trovato"); + if (!projects || projects.length === 0) return []; for (let i = 0; i < projects.length; i++) { projects[i] = await populateMembers(projects[i]);