feat: Add tickets module and PayPal integration

Introduces a new 'Tickets' module for users to submit and manage issues within their condominium. This includes defining ticket types, statuses, priorities, and categories.

Additionally, this commit integrates PayPal as a payment option for family fee payments, enabling users to pay directly via PayPal using their client ID.

Key changes:
- Added `Ticket` related types and enums.
- Implemented `TicketService` functions for CRUD operations.
- Integrated `@paypal/react-paypal-js` library.
- Added `paypalClientId` to `AppSettings` and `Condo` types.
- Updated `FamilyDetail` page to include PayPal payment option.
- Added 'Segnalazioni' navigation link to `Layout`.
This commit is contained in:
2025-12-07 19:49:59 +01:00
parent 2566b406e1
commit 5311400615
14 changed files with 977 additions and 146 deletions

View File

@@ -60,6 +60,7 @@ const initDb = async () => {
console.log(`Database connected successfully using ${DB_CLIENT}.`);
const TIMESTAMP_TYPE = 'TIMESTAMP';
const LONG_TEXT_TYPE = DB_CLIENT === 'postgres' ? 'TEXT' : 'LONGTEXT'; // For base64 files
// 0. Settings Table (Global App Settings)
await connection.query(`
@@ -82,21 +83,26 @@ const initDb = async () => {
zip_code VARCHAR(20),
notes TEXT,
iban VARCHAR(50),
paypal_client_id VARCHAR(255),
default_monthly_quota DECIMAL(10, 2) DEFAULT 100.00,
image VARCHAR(255),
created_at ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP
)
`);
// Migration for condos: Add new address fields
// Migration for condos: Add new address fields and paypal_client_id
try {
let hasCity = false;
let hasPayPal = false;
if (DB_CLIENT === 'postgres') {
const [cols] = await connection.query("SELECT column_name FROM information_schema.columns WHERE table_name='condos'");
hasCity = cols.some(c => c.column_name === 'city');
hasPayPal = cols.some(c => c.column_name === 'paypal_client_id');
} else {
const [cols] = await connection.query("SHOW COLUMNS FROM condos");
hasCity = cols.some(c => c.Field === 'city');
hasPayPal = cols.some(c => c.Field === 'paypal_client_id');
}
if (!hasCity) {
@@ -107,6 +113,12 @@ const initDb = async () => {
await connection.query("ALTER TABLE condos ADD COLUMN zip_code VARCHAR(20)");
await connection.query("ALTER TABLE condos ADD COLUMN notes TEXT");
}
if (!hasPayPal) {
console.log('Migrating: Adding PayPal fields to condos...');
await connection.query("ALTER TABLE condos ADD COLUMN paypal_client_id VARCHAR(255)");
}
} catch(e) { console.warn("Condos migration warning:", e.message); }
@@ -254,6 +266,37 @@ const initDb = async () => {
FOREIGN KEY (notice_id) REFERENCES notices(id) ON DELETE CASCADE
)
`);
// 8. Tickets Table (Segnalazioni)
await connection.query(`
CREATE TABLE IF NOT EXISTS tickets (
id VARCHAR(36) PRIMARY KEY,
condo_id VARCHAR(36) NOT NULL,
user_id VARCHAR(36) NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
status VARCHAR(20) DEFAULT 'OPEN',
priority VARCHAR(20) DEFAULT 'MEDIUM',
category VARCHAR(20) DEFAULT 'OTHER',
created_at ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP,
updated_at ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (condo_id) REFERENCES condos(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)
`);
// 9. Ticket Attachments Table
await connection.query(`
CREATE TABLE IF NOT EXISTS ticket_attachments (
id VARCHAR(36) PRIMARY KEY,
ticket_id VARCHAR(36) NOT NULL,
file_name VARCHAR(255) NOT NULL,
file_type VARCHAR(100),
data ${LONG_TEXT_TYPE}, -- Base64 encoded file
created_at ${TIMESTAMP_TYPE} DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (ticket_id) REFERENCES tickets(id) ON DELETE CASCADE
)
`);
// --- SEEDING ---
const [rows] = await connection.query('SELECT * FROM settings WHERE id = 1');
@@ -289,4 +332,4 @@ const initDb = async () => {
}
};
module.exports = { pool: dbInterface, initDb };
module.exports = { pool: dbInterface, initDb };