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:
@@ -2,7 +2,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { CondoService } from '../services/mockDb';
|
||||
import { AppSettings, Family, User, AlertDefinition, Condo, Notice, NoticeIconType, NoticeRead } from '../types';
|
||||
import { Save, Building, Coins, Plus, Pencil, Trash2, X, CalendarCheck, AlertTriangle, User as UserIcon, Server, Bell, Clock, FileText, Lock, Megaphone, CheckCircle2, Info, Hammer, Link as LinkIcon, Eye, Calendar, List, UserCog, Mail, Power, MapPin } from 'lucide-react';
|
||||
import { Save, Building, Coins, Plus, Pencil, Trash2, X, CalendarCheck, AlertTriangle, User as UserIcon, Server, Bell, Clock, FileText, Lock, Megaphone, CheckCircle2, Info, Hammer, Link as LinkIcon, Eye, Calendar, List, UserCog, Mail, Power, MapPin, CreditCard } from 'lucide-react';
|
||||
|
||||
export const SettingsPage: React.FC = () => {
|
||||
const currentUser = CondoService.getCurrentUser();
|
||||
@@ -40,6 +40,7 @@ export const SettingsPage: React.FC = () => {
|
||||
province: '',
|
||||
zipCode: '',
|
||||
notes: '',
|
||||
paypalClientId: '',
|
||||
defaultMonthlyQuota: 100
|
||||
});
|
||||
|
||||
@@ -235,7 +236,7 @@ export const SettingsPage: React.FC = () => {
|
||||
// --- Condo Management Handlers ---
|
||||
const openAddCondoModal = () => {
|
||||
setEditingCondo(null);
|
||||
setCondoForm({ name: '', address: '', streetNumber: '', city: '', province: '', zipCode: '', notes: '', defaultMonthlyQuota: 100 });
|
||||
setCondoForm({ name: '', address: '', streetNumber: '', city: '', province: '', zipCode: '', notes: '', paypalClientId: '', defaultMonthlyQuota: 100 });
|
||||
setShowCondoModal(true);
|
||||
};
|
||||
|
||||
@@ -249,6 +250,7 @@ export const SettingsPage: React.FC = () => {
|
||||
province: c.province || '',
|
||||
zipCode: c.zipCode || '',
|
||||
notes: c.notes || '',
|
||||
paypalClientId: c.paypalClientId || '',
|
||||
defaultMonthlyQuota: c.defaultMonthlyQuota
|
||||
});
|
||||
setShowCondoModal(true);
|
||||
@@ -266,6 +268,7 @@ export const SettingsPage: React.FC = () => {
|
||||
province: condoForm.province,
|
||||
zipCode: condoForm.zipCode,
|
||||
notes: condoForm.notes,
|
||||
paypalClientId: condoForm.paypalClientId,
|
||||
defaultMonthlyQuota: condoForm.defaultMonthlyQuota
|
||||
};
|
||||
|
||||
@@ -607,6 +610,11 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Rest of the file (Families, Users, Notices, Alerts, SMTP Tabs) remains mostly same, just update modal */}
|
||||
{/* ... (Existing Tabs Code for Families, Users, Notices, Alerts, SMTP) ... */}
|
||||
|
||||
{/* Only change is inside CONDO MODAL */}
|
||||
|
||||
{/* Families Tab */}
|
||||
{isAdmin && activeTab === 'families' && (
|
||||
<div className="space-y-4 animate-fade-in">
|
||||
@@ -789,7 +797,7 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ALERT MODAL */}
|
||||
{/* ALERT MODAL (Existing) */}
|
||||
{showAlertModal && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-md p-6 animate-in fade-in zoom-in duration-200">
|
||||
@@ -826,7 +834,7 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* NOTICE MODAL */}
|
||||
{/* NOTICE MODAL (Existing) */}
|
||||
{showNoticeModal && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-lg p-6 animate-in fade-in zoom-in duration-200">
|
||||
@@ -868,7 +876,7 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* READ DETAILS MODAL */}
|
||||
{/* READ DETAILS MODAL (Existing) */}
|
||||
{showReadDetailsModal && selectedNoticeId && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-md p-6 animate-in fade-in zoom-in duration-200">
|
||||
@@ -907,7 +915,7 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* USER MODAL */}
|
||||
{/* USER MODAL (Existing) */}
|
||||
{showUserModal && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-md p-6 animate-in fade-in zoom-in duration-200">
|
||||
@@ -950,10 +958,10 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* CONDO MODAL */}
|
||||
{/* CONDO MODAL (UPDATED) */}
|
||||
{showCondoModal && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-lg p-6 animate-in fade-in zoom-in duration-200">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-lg p-6 animate-in fade-in zoom-in duration-200 overflow-y-auto max-h-[90vh]">
|
||||
<h3 className="font-bold text-lg mb-4 text-slate-800">{editingCondo ? 'Modifica Condominio' : 'Nuovo Condominio'}</h3>
|
||||
<form onSubmit={handleCondoSubmit} className="space-y-4">
|
||||
|
||||
@@ -985,9 +993,27 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* PayPal Integration Section */}
|
||||
<div className="bg-blue-50 p-3 rounded-lg border border-blue-100">
|
||||
<div className="flex items-center gap-2 mb-2 text-blue-800">
|
||||
<CreditCard className="w-4 h-4"/>
|
||||
<span className="text-xs font-bold uppercase">Configurazione Pagamenti</span>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-600 block mb-1">PayPal Client ID (REST API App)</label>
|
||||
<input
|
||||
className="w-full border p-2 rounded text-slate-700 text-sm"
|
||||
placeholder="Es: Afg... (Ottienilo da developer.paypal.com)"
|
||||
value={condoForm.paypalClientId}
|
||||
onChange={e => setCondoForm({...condoForm, paypalClientId: e.target.value})}
|
||||
/>
|
||||
<p className="text-[10px] text-slate-500 mt-1">Necessario per abilitare i pagamenti online delle rate.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Notes */}
|
||||
<div>
|
||||
<textarea className="w-full border p-2.5 rounded-lg text-slate-700 h-20" placeholder="Note (opzionali)" value={condoForm.notes} onChange={e => setCondoForm({...condoForm, notes: e.target.value})} />
|
||||
<textarea className="w-full border p-2.5 rounded-lg text-slate-700 h-16" placeholder="Note (opzionali)" value={condoForm.notes} onChange={e => setCondoForm({...condoForm, notes: e.target.value})} />
|
||||
</div>
|
||||
|
||||
{/* Quota */}
|
||||
@@ -1005,7 +1031,7 @@ export const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* FAMILY MODAL */}
|
||||
{/* FAMILY MODAL (Existing) */}
|
||||
{showFamilyModal && (
|
||||
<div className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4 backdrop-blur-sm">
|
||||
<div className="bg-white rounded-2xl shadow-xl w-full max-w-lg p-6">
|
||||
@@ -1068,4 +1094,4 @@ export const SettingsPage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user