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:
47
server/db.js
47
server/db.js
@@ -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 };
|
||||
Reference in New Issue
Block a user