Release v3.1.4 - Mode terrain et génération PDF #10
598
api/docs/geo_app.sql
Normal file
598
api/docs/geo_app.sql
Normal file
@@ -0,0 +1,598 @@
|
|||||||
|
-- -------------------------------------------------------------
|
||||||
|
-- TablePlus 6.4.8(608)
|
||||||
|
--
|
||||||
|
-- https://tableplus.com/
|
||||||
|
--
|
||||||
|
-- Database: geo_app
|
||||||
|
-- Generation Time: 2025-06-09 18:03:43.5140
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
|
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE `chat_anonymous_users` (
|
||||||
|
`id` varchar(50) NOT NULL,
|
||||||
|
`device_id` varchar(100) NOT NULL,
|
||||||
|
`name` varchar(100) DEFAULT NULL,
|
||||||
|
`email` varchar(100) DEFAULT NULL,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`converted_to_user_id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_device_id` (`device_id`),
|
||||||
|
KEY `idx_converted_user` (`converted_to_user_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_attachments` (
|
||||||
|
`id` varchar(50) NOT NULL,
|
||||||
|
`fk_message` varchar(50) NOT NULL,
|
||||||
|
`file_name` varchar(255) NOT NULL,
|
||||||
|
`file_path` varchar(500) NOT NULL,
|
||||||
|
`file_type` varchar(100) NOT NULL,
|
||||||
|
`file_size` int(10) unsigned NOT NULL,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_message` (`fk_message`),
|
||||||
|
CONSTRAINT `fk_chat_attachments_message` FOREIGN KEY (`fk_message`) REFERENCES `chat_messages` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_audience_targets` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_room` varchar(50) NOT NULL,
|
||||||
|
`target_type` enum('role','entity','all','combined') NOT NULL DEFAULT 'all',
|
||||||
|
`target_id` varchar(50) DEFAULT NULL,
|
||||||
|
`role_filter` varchar(20) DEFAULT NULL,
|
||||||
|
`entity_filter` varchar(50) DEFAULT NULL,
|
||||||
|
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_room` (`fk_room`),
|
||||||
|
KEY `idx_type` (`target_type`),
|
||||||
|
CONSTRAINT `fk_chat_audience_targets_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_broadcast_lists` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_room` varchar(50) NOT NULL,
|
||||||
|
`name` varchar(100) NOT NULL,
|
||||||
|
`description` text DEFAULT NULL,
|
||||||
|
`fk_user_creator` int(10) unsigned NOT NULL,
|
||||||
|
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_room` (`fk_room`),
|
||||||
|
KEY `idx_user_creator` (`fk_user_creator`),
|
||||||
|
CONSTRAINT `fk_chat_broadcast_lists_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE `chat_messages` (
|
||||||
|
`id` varchar(50) NOT NULL,
|
||||||
|
`fk_room` varchar(50) NOT NULL,
|
||||||
|
`fk_user` int(10) unsigned DEFAULT NULL,
|
||||||
|
`sender_type` enum('user','anonymous','system') NOT NULL DEFAULT 'user',
|
||||||
|
`content` text DEFAULT NULL,
|
||||||
|
`content_type` enum('text','image','file') NOT NULL DEFAULT 'text',
|
||||||
|
`date_sent` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`date_delivered` timestamp NULL DEFAULT NULL,
|
||||||
|
`date_read` timestamp NULL DEFAULT NULL,
|
||||||
|
`statut` enum('envoye','livre','lu','error') NOT NULL DEFAULT 'envoye',
|
||||||
|
`is_announcement` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_room` (`fk_room`),
|
||||||
|
KEY `idx_user` (`fk_user`),
|
||||||
|
KEY `idx_date` (`date_sent`),
|
||||||
|
KEY `idx_status` (`statut`),
|
||||||
|
KEY `idx_messages_unread` (`fk_room`,`statut`),
|
||||||
|
CONSTRAINT `fk_chat_messages_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_notifications` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_user` int(10) unsigned NOT NULL,
|
||||||
|
`fk_message` varchar(50) DEFAULT NULL,
|
||||||
|
`fk_room` varchar(50) DEFAULT NULL,
|
||||||
|
`type` varchar(50) NOT NULL,
|
||||||
|
`contenu` text DEFAULT NULL,
|
||||||
|
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`date_lecture` timestamp NULL DEFAULT NULL,
|
||||||
|
`statut` enum('non_lue','lue') NOT NULL DEFAULT 'non_lue',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_user` (`fk_user`),
|
||||||
|
KEY `idx_message` (`fk_message`),
|
||||||
|
KEY `idx_room` (`fk_room`),
|
||||||
|
KEY `idx_statut` (`statut`),
|
||||||
|
KEY `idx_notifications_unread` (`fk_user`,`statut`),
|
||||||
|
CONSTRAINT `fk_chat_notifications_message` FOREIGN KEY (`fk_message`) REFERENCES `chat_messages` (`id`) ON DELETE SET NULL,
|
||||||
|
CONSTRAINT `fk_chat_notifications_room` FOREIGN KEY (`fk_room`) REFERENCES `chat_rooms` (`id`) ON DELETE SET NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_offline_queue` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(10) unsigned NOT NULL,
|
||||||
|
`operation_type` varchar(50) NOT NULL,
|
||||||
|
`operation_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`operation_data`)),
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`processed_at` timestamp NULL DEFAULT NULL,
|
||||||
|
`status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending',
|
||||||
|
`error_message` text DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_created_at` (`created_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_participants` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`id_room` varchar(50) NOT NULL,
|
||||||
|
`id_user` int(10) unsigned DEFAULT NULL,
|
||||||
|
`anonymous_id` varchar(50) DEFAULT NULL,
|
||||||
|
`role` enum('administrateur','participant','en_lecture_seule') NOT NULL DEFAULT 'participant',
|
||||||
|
`date_ajout` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`notification_activee` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||||
|
`last_read_message_id` varchar(50) DEFAULT NULL,
|
||||||
|
`via_target` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`can_reply` tinyint(1) unsigned DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uc_room_user` (`id_room`,`id_user`),
|
||||||
|
KEY `idx_room` (`id_room`),
|
||||||
|
KEY `idx_user` (`id_user`),
|
||||||
|
KEY `idx_anonymous_id` (`anonymous_id`),
|
||||||
|
KEY `idx_participants_active` (`id_room`,`id_user`,`notification_activee`),
|
||||||
|
CONSTRAINT `fk_chat_participants_room` FOREIGN KEY (`id_room`) REFERENCES `chat_rooms` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_read_messages` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_message` varchar(50) NOT NULL,
|
||||||
|
`fk_user` int(10) unsigned NOT NULL,
|
||||||
|
`date_read` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uc_message_user` (`fk_message`,`fk_user`),
|
||||||
|
KEY `idx_message` (`fk_message`),
|
||||||
|
KEY `idx_user` (`fk_user`),
|
||||||
|
CONSTRAINT `fk_chat_read_messages_message` FOREIGN KEY (`fk_message`) REFERENCES `chat_messages` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `chat_rooms` (
|
||||||
|
`id` varchar(50) NOT NULL,
|
||||||
|
`type` enum('privee','groupe','liste_diffusion','broadcast','announcement') NOT NULL,
|
||||||
|
`title` varchar(100) DEFAULT NULL,
|
||||||
|
`date_creation` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`fk_user` int(10) unsigned NOT NULL,
|
||||||
|
`fk_entite` int(10) unsigned DEFAULT NULL,
|
||||||
|
`statut` enum('active','archive') NOT NULL DEFAULT 'active',
|
||||||
|
`description` text DEFAULT NULL,
|
||||||
|
`reply_permission` enum('all','admins_only','sender_only','none') NOT NULL DEFAULT 'all',
|
||||||
|
`is_pinned` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`expiry_date` timestamp NULL DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_user` (`fk_user`),
|
||||||
|
KEY `idx_entite` (`fk_entite`),
|
||||||
|
KEY `idx_type` (`type`),
|
||||||
|
KEY `idx_statut` (`statut`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `email_counter` (
|
||||||
|
`id` int(10) unsigned NOT NULL DEFAULT 1,
|
||||||
|
`hour_start` timestamp NULL DEFAULT NULL,
|
||||||
|
`count` int(10) unsigned DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `email_queue` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_pass` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`to_email` varchar(255) DEFAULT NULL,
|
||||||
|
`subject` varchar(255) DEFAULT NULL,
|
||||||
|
`body` text DEFAULT NULL,
|
||||||
|
`headers` text DEFAULT NULL,
|
||||||
|
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||||
|
`status` enum('pending','sent','failed') DEFAULT 'pending',
|
||||||
|
`attempts` int(10) unsigned DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `entites` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`encrypted_name` varchar(255) DEFAULT NULL,
|
||||||
|
`adresse1` varchar(45) DEFAULT '',
|
||||||
|
`adresse2` varchar(45) DEFAULT '',
|
||||||
|
`code_postal` varchar(5) DEFAULT '',
|
||||||
|
`ville` varchar(45) DEFAULT '',
|
||||||
|
`fk_region` int(10) unsigned DEFAULT NULL,
|
||||||
|
`fk_type` int(10) unsigned DEFAULT 1,
|
||||||
|
`encrypted_phone` varchar(128) DEFAULT '',
|
||||||
|
`encrypted_mobile` varchar(128) DEFAULT '',
|
||||||
|
`encrypted_email` varchar(255) DEFAULT '',
|
||||||
|
`gps_lat` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`gps_lng` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`chk_stripe` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`encrypted_stripe_id` varchar(255) DEFAULT '',
|
||||||
|
`encrypted_iban` varchar(255) DEFAULT '',
|
||||||
|
`encrypted_bic` varchar(128) DEFAULT '',
|
||||||
|
`chk_demo` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
`chk_mdp_manuel` tinyint(1) unsigned NOT NULL DEFAULT 1 COMMENT 'Gestion des mots de passe manuelle O/N',
|
||||||
|
`chk_copie_mail_recu` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`chk_accept_sms` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `entites_ibfk_1` (`fk_region`),
|
||||||
|
KEY `entites_ibfk_2` (`fk_type`),
|
||||||
|
CONSTRAINT `entites_ibfk_1` FOREIGN KEY (`fk_region`) REFERENCES `x_regions` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `entites_ibfk_2` FOREIGN KEY (`fk_type`) REFERENCES `x_entites_types` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1230 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `medias` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`support` varchar(45) NOT NULL DEFAULT '',
|
||||||
|
`support_id` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fichier` varchar(250) NOT NULL DEFAULT '',
|
||||||
|
`description` varchar(100) NOT NULL DEFAULT '',
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
|
||||||
|
`fk_user_modif` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=176 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `ope_pass` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_operation` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_sector` int(10) unsigned DEFAULT 0,
|
||||||
|
`fk_user` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_adresse` varchar(25) DEFAULT '' COMMENT 'adresses.cp??.id',
|
||||||
|
`passed_at` timestamp NULL DEFAULT NULL COMMENT 'Date du passage',
|
||||||
|
`fk_type` int(10) unsigned DEFAULT 0,
|
||||||
|
`numero` varchar(10) NOT NULL DEFAULT '',
|
||||||
|
`rue` varchar(75) NOT NULL DEFAULT '',
|
||||||
|
`rue_bis` varchar(1) NOT NULL DEFAULT '',
|
||||||
|
`ville` varchar(75) NOT NULL DEFAULT '',
|
||||||
|
`fk_habitat` int(10) unsigned DEFAULT 1,
|
||||||
|
`appt` varchar(5) DEFAULT '',
|
||||||
|
`niveau` varchar(5) DEFAULT '',
|
||||||
|
`residence` varchar(75) DEFAULT '',
|
||||||
|
`gps_lat` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`gps_lng` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`encrypted_name` varchar(255) NOT NULL DEFAULT '',
|
||||||
|
`montant` decimal(7,2) NOT NULL DEFAULT 0.00,
|
||||||
|
`fk_type_reglement` int(10) unsigned DEFAULT 1,
|
||||||
|
`remarque` text DEFAULT '',
|
||||||
|
`encrypted_email` varchar(255) DEFAULT '',
|
||||||
|
`nom_recu` varchar(50) DEFAULT NULL,
|
||||||
|
`date_recu` timestamp NULL DEFAULT NULL COMMENT 'Date de réception',
|
||||||
|
`date_creat_recu` timestamp NULL DEFAULT NULL COMMENT 'Date de création du reçu',
|
||||||
|
`date_sent_recu` timestamp NULL DEFAULT NULL COMMENT 'Date envoi du reçu',
|
||||||
|
`email_erreur` varchar(30) DEFAULT '',
|
||||||
|
`chk_email_sent` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`encrypted_phone` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`is_striped` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`docremis` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`date_repasser` timestamp NULL DEFAULT NULL COMMENT 'Date prévue pour repasser',
|
||||||
|
`nb_passages` int(11) DEFAULT 1 COMMENT 'Nb passages pour les a repasser',
|
||||||
|
`chk_gps_maj` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`chk_map_create` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`chk_mobile` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`chk_synchro` tinyint(1) unsigned DEFAULT 1 COMMENT 'chk synchro entre web et appli',
|
||||||
|
`chk_api_adresse` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`chk_maj_adresse` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`anomalie` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `fk_operation` (`fk_operation`),
|
||||||
|
KEY `fk_sector` (`fk_sector`),
|
||||||
|
KEY `fk_user` (`fk_user`),
|
||||||
|
KEY `fk_type` (`fk_type`),
|
||||||
|
KEY `fk_type_reglement` (`fk_type_reglement`),
|
||||||
|
KEY `email` (`encrypted_email`),
|
||||||
|
CONSTRAINT `ope_pass_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `ope_pass_ibfk_2` FOREIGN KEY (`fk_sector`) REFERENCES `ope_sectors` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `ope_pass_ibfk_3` FOREIGN KEY (`fk_user`) REFERENCES `users` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `ope_pass_ibfk_4` FOREIGN KEY (`fk_type_reglement`) REFERENCES `x_types_reglements` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=19499566 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `ope_pass_histo` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_pass` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`date_histo` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date historique',
|
||||||
|
`sujet` varchar(50) DEFAULT NULL,
|
||||||
|
`remarque` varchar(250) NOT NULL DEFAULT '',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `ope_pass_histo_fk_pass_IDX` (`fk_pass`) USING BTREE,
|
||||||
|
KEY `ope_pass_histo_date_histo_IDX` (`date_histo`) USING BTREE,
|
||||||
|
CONSTRAINT `ope_pass_histo_ibfk_1` FOREIGN KEY (`fk_pass`) REFERENCES `ope_pass` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=6752 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `ope_sectors` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_operation` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_old_sector` int(10) unsigned DEFAULT NULL,
|
||||||
|
`libelle` varchar(75) NOT NULL DEFAULT '',
|
||||||
|
`sector` text NOT NULL DEFAULT '',
|
||||||
|
`color` varchar(7) NOT NULL DEFAULT '#4B77BE',
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id` (`id`),
|
||||||
|
KEY `fk_operation` (`fk_operation`),
|
||||||
|
CONSTRAINT `ope_sectors_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=27675 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `ope_users` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_operation` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_user` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||||
|
KEY `ope_users_ibfk_1` (`fk_operation`),
|
||||||
|
KEY `ope_users_ibfk_2` (`fk_user`),
|
||||||
|
CONSTRAINT `ope_users_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `ope_users_ibfk_2` FOREIGN KEY (`fk_user`) REFERENCES `users` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=199006 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `ope_users_sectors` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_operation` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_user` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_sector` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id` (`id`),
|
||||||
|
KEY `fk_operation` (`fk_operation`),
|
||||||
|
KEY `fk_user` (`fk_user`),
|
||||||
|
KEY `fk_sector` (`fk_sector`),
|
||||||
|
CONSTRAINT `ope_users_sectors_ibfk_1` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `ope_users_sectors_ibfk_2` FOREIGN KEY (`fk_user`) REFERENCES `users` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `ope_users_sectors_ibfk_3` FOREIGN KEY (`fk_sector`) REFERENCES `ope_sectors` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=48082 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `ope_users_suivis` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_operation` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_user` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`date_suivi` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date du suivi',
|
||||||
|
`gps_lat` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`gps_lng` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`vitesse` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `operations` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_entite` int(10) unsigned NOT NULL DEFAULT 1,
|
||||||
|
`libelle` varchar(75) NOT NULL DEFAULT '',
|
||||||
|
`date_deb` date NOT NULL DEFAULT '0000-00-00',
|
||||||
|
`date_fin` date NOT NULL DEFAULT '0000-00-00',
|
||||||
|
`chk_distinct_sectors` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `fk_entite` (`fk_entite`),
|
||||||
|
KEY `date_deb` (`date_deb`),
|
||||||
|
CONSTRAINT `operations_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=3121 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `params` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`libelle` varchar(35) NOT NULL DEFAULT '',
|
||||||
|
`valeur` varchar(255) NOT NULL DEFAULT '',
|
||||||
|
`aide` varchar(150) NOT NULL DEFAULT '',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `sectors_adresses` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_adresse` varchar(25) DEFAULT NULL COMMENT 'adresses.cp??.id',
|
||||||
|
`osm_id` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`fk_sector` int(10) unsigned NOT NULL DEFAULT 0,
|
||||||
|
`osm_name` varchar(50) NOT NULL DEFAULT '',
|
||||||
|
`numero` varchar(5) NOT NULL DEFAULT '',
|
||||||
|
`rue_bis` varchar(5) NOT NULL DEFAULT '',
|
||||||
|
`rue` varchar(60) NOT NULL DEFAULT '',
|
||||||
|
`cp` varchar(5) NOT NULL DEFAULT '',
|
||||||
|
`ville` varchar(60) NOT NULL DEFAULT '',
|
||||||
|
`gps_lat` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`gps_lng` varchar(20) NOT NULL DEFAULT '',
|
||||||
|
`osm_date_creat` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `sectors_adresses_fk_sector_index` (`fk_sector`),
|
||||||
|
KEY `sectors_adresses_numero_index` (`numero`),
|
||||||
|
KEY `sectors_adresses_rue_index` (`rue`),
|
||||||
|
KEY `sectors_adresses_ville_index` (`ville`),
|
||||||
|
CONSTRAINT `sectors_adresses_ibfk_1` FOREIGN KEY (`fk_sector`) REFERENCES `ope_sectors` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1562946 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `users` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_entite` int(10) unsigned DEFAULT 1,
|
||||||
|
`fk_role` int(10) unsigned DEFAULT 1,
|
||||||
|
`fk_titre` int(10) unsigned DEFAULT 1,
|
||||||
|
`encrypted_name` varchar(255) DEFAULT NULL,
|
||||||
|
`first_name` varchar(45) DEFAULT NULL,
|
||||||
|
`sect_name` varchar(60) DEFAULT '',
|
||||||
|
`encrypted_user_name` varchar(128) DEFAULT '',
|
||||||
|
`user_pass_hash` varchar(60) DEFAULT NULL,
|
||||||
|
`encrypted_phone` varchar(128) DEFAULT NULL,
|
||||||
|
`encrypted_mobile` varchar(128) DEFAULT NULL,
|
||||||
|
`encrypted_email` varchar(255) DEFAULT '',
|
||||||
|
`chk_alert_email` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
`chk_suivi` tinyint(1) unsigned DEFAULT 0,
|
||||||
|
`date_naissance` date DEFAULT NULL,
|
||||||
|
`date_embauche` date DEFAULT NULL,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||||
|
`fk_user_creat` int(10) unsigned DEFAULT NULL,
|
||||||
|
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||||
|
`fk_user_modif` int(10) unsigned DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `fk_entite` (`fk_entite`),
|
||||||
|
KEY `username` (`encrypted_user_name`),
|
||||||
|
KEY `users_ibfk_2` (`fk_role`),
|
||||||
|
KEY `users_ibfk_3` (`fk_titre`),
|
||||||
|
CONSTRAINT `users_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `users_ibfk_2` FOREIGN KEY (`fk_role`) REFERENCES `x_users_roles` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `users_ibfk_3` FOREIGN KEY (`fk_titre`) REFERENCES `x_users_titres` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=10027748 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_departements` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`code` varchar(3) DEFAULT NULL,
|
||||||
|
`fk_region` int(10) unsigned DEFAULT 1,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||||
|
KEY `x_departements_ibfk_1` (`fk_region`),
|
||||||
|
CONSTRAINT `x_departements_ibfk_1` FOREIGN KEY (`fk_region`) REFERENCES `x_regions` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=105 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_devises` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`code` varchar(3) DEFAULT NULL,
|
||||||
|
`symbole` varchar(6) DEFAULT NULL,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_entites_types` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_pays` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`code` varchar(3) DEFAULT NULL,
|
||||||
|
`fk_continent` int(10) unsigned DEFAULT NULL,
|
||||||
|
`fk_devise` int(10) unsigned DEFAULT 1,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||||
|
KEY `x_pays_ibfk_1` (`fk_devise`),
|
||||||
|
CONSTRAINT `x_pays_ibfk_1` FOREIGN KEY (`fk_devise`) REFERENCES `x_devises` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Table des pays avec leurs codes' `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_regions` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_pays` int(10) unsigned DEFAULT 1,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`libelle_long` varchar(45) DEFAULT NULL,
|
||||||
|
`table_osm` varchar(45) DEFAULT NULL,
|
||||||
|
`departements` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||||
|
KEY `x_regions_ibfk_1` (`fk_pays`),
|
||||||
|
CONSTRAINT `x_regions_ibfk_1` FOREIGN KEY (`fk_pays`) REFERENCES `x_pays` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_types_passages` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`libelle` varchar(10) DEFAULT NULL,
|
||||||
|
`color_button` varchar(15) DEFAULT NULL,
|
||||||
|
`color_mark` varchar(15) DEFAULT NULL,
|
||||||
|
`color_table` varchar(15) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned NOT NULL DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_types_reglements` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_users_roles` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Les différents rôles des utilisateurs' `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_users_titres` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`libelle` varchar(45) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Les différents titres des utilisateurs' `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `x_villes` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`fk_departement` int(10) unsigned DEFAULT 1,
|
||||||
|
`libelle` varchar(65) DEFAULT NULL,
|
||||||
|
`code_postal` varchar(5) DEFAULT NULL,
|
||||||
|
`code_insee` varchar(5) DEFAULT NULL,
|
||||||
|
`chk_active` tinyint(1) unsigned DEFAULT 1,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||||
|
KEY `x_villes_ibfk_1` (`fk_departement`),
|
||||||
|
CONSTRAINT `x_villes_ibfk_1` FOREIGN KEY (`fk_departement`) REFERENCES `x_departements` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=38950 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE TABLE `z_sessions` (
|
||||||
|
`sid` text NOT NULL,
|
||||||
|
`fk_user` int(11) NOT NULL,
|
||||||
|
`role` varchar(10) DEFAULT NULL,
|
||||||
|
`date_modified` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
|
`ip` varchar(50) NOT NULL,
|
||||||
|
`browser` varchar(150) NOT NULL,
|
||||||
|
`data` mediumtext DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||||
|
|
||||||
|
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`%` SQL SECURITY DEFINER VIEW `chat_conversations_unread` AS select `r`.`id` AS `id`,`r`.`type` AS `type`,`r`.`title` AS `title`,`r`.`date_creation` AS `date_creation`,`r`.`fk_user` AS `fk_user`,`r`.`fk_entite` AS `fk_entite`,`r`.`statut` AS `statut`,`r`.`description` AS `description`,`r`.`reply_permission` AS `reply_permission`,`r`.`is_pinned` AS `is_pinned`,`r`.`expiry_date` AS `expiry_date`,`r`.`updated_at` AS `updated_at`,count(distinct `m`.`id`) AS `total_messages`,count(distinct `rm`.`id`) AS `read_messages`,count(distinct `m`.`id`) - count(distinct `rm`.`id`) AS `unread_messages`,(select `geo_app`.`chat_messages`.`date_sent` from `chat_messages` where `geo_app`.`chat_messages`.`fk_room` = `r`.`id` order by `geo_app`.`chat_messages`.`date_sent` desc limit 1) AS `last_message_date` from ((`chat_rooms` `r` left join `chat_messages` `m` on(`r`.`id` = `m`.`fk_room`)) left join `chat_read_messages` `rm` on(`m`.`id` = `rm`.`fk_message`)) group by `r`.`id`;
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||||
|
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
@@ -386,9 +386,10 @@ class EntiteController {
|
|||||||
* Met à jour une entité existante avec les données fournies
|
* Met à jour une entité existante avec les données fournies
|
||||||
* Seuls les administrateurs (rôle > 2) peuvent modifier certains champs
|
* Seuls les administrateurs (rôle > 2) peuvent modifier certains champs
|
||||||
*
|
*
|
||||||
|
* @param string $id ID de l'entité depuis l'URL
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function updateEntite(): void {
|
public function updateEntite(string $id = null): void {
|
||||||
try {
|
try {
|
||||||
// Vérifier l'authentification et les droits d'accès
|
// Vérifier l'authentification et les droits d'accès
|
||||||
$userId = Session::getUserId();
|
$userId = Session::getUserId();
|
||||||
@@ -419,7 +420,10 @@ class EntiteController {
|
|||||||
// Récupérer les données de la requête
|
// Récupérer les données de la requête
|
||||||
$data = Request::getJson();
|
$data = Request::getJson();
|
||||||
|
|
||||||
if (!isset($data['id']) || empty($data['id'])) {
|
// Priorité à l'ID de l'URL, sinon utiliser celui du JSON
|
||||||
|
$entiteId = $id ? (int)$id : (isset($data['id']) ? (int)$data['id'] : null);
|
||||||
|
|
||||||
|
if (!$entiteId) {
|
||||||
Response::json([
|
Response::json([
|
||||||
'status' => 'error',
|
'status' => 'error',
|
||||||
'message' => 'ID de l\'entité requis'
|
'message' => 'ID de l\'entité requis'
|
||||||
@@ -427,8 +431,6 @@ class EntiteController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$entiteId = (int)$data['id'];
|
|
||||||
|
|
||||||
// Récupérer les données actuelles de l'entité pour vérifier si l'adresse a changé
|
// Récupérer les données actuelles de l'entité pour vérifier si l'adresse a changé
|
||||||
$stmt = $this->db->prepare('SELECT adresse1, adresse2, code_postal, ville FROM entites WHERE id = ?');
|
$stmt = $this->db->prepare('SELECT adresse1, adresse2, code_postal, ville FROM entites WHERE id = ?');
|
||||||
$stmt->execute([$entiteId]);
|
$stmt->execute([$entiteId]);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class Router {
|
|||||||
$this->get('entites', ['EntiteController', 'getEntites']);
|
$this->get('entites', ['EntiteController', 'getEntites']);
|
||||||
$this->get('entites/:id', ['EntiteController', 'getEntiteById']);
|
$this->get('entites/:id', ['EntiteController', 'getEntiteById']);
|
||||||
$this->get('entites/postal/:code', ['EntiteController', 'getEntiteByPostalCode']);
|
$this->get('entites/postal/:code', ['EntiteController', 'getEntiteByPostalCode']);
|
||||||
|
$this->put('entites/:id', ['EntiteController', 'updateEntite']);
|
||||||
|
|
||||||
// Routes villes
|
// Routes villes
|
||||||
$this->get('villes', ['VilleController', 'searchVillesByPostalCode']);
|
$this->get('villes', ['VilleController', 'searchVillesByPostalCode']);
|
||||||
@@ -187,7 +188,8 @@ class Router {
|
|||||||
error_log("Routes disponibles pour $method: " . implode(', ', array_keys($this->routes[$method])));
|
error_log("Routes disponibles pour $method: " . implode(', ', array_keys($this->routes[$method])));
|
||||||
|
|
||||||
foreach ($this->routes[$method] as $route => $handler) {
|
foreach ($this->routes[$method] as $route => $handler) {
|
||||||
$pattern = preg_replace('/{[^}]+}/', '([^/]+)', $route);
|
// Correction: utiliser :param au lieu de {param}
|
||||||
|
$pattern = preg_replace('/:([^\/]+)/', '([^/]+)', $route);
|
||||||
$pattern = "@^" . $pattern . "$@D";
|
$pattern = "@^" . $pattern . "$@D";
|
||||||
error_log("Test pattern: $pattern contre uri: $uri");
|
error_log("Test pattern: $pattern contre uri: $uri");
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
class AnonymousUserModelAdapter extends TypeAdapter<AnonymousUserModel> {
|
class AnonymousUserModelAdapter extends TypeAdapter<AnonymousUserModel> {
|
||||||
@override
|
@override
|
||||||
final int typeId = 24;
|
final int typeId = 23;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AnonymousUserModel read(BinaryReader reader) {
|
AnonymousUserModel read(BinaryReader reader) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
class AudienceTargetModelAdapter extends TypeAdapter<AudienceTargetModel> {
|
class AudienceTargetModelAdapter extends TypeAdapter<AudienceTargetModel> {
|
||||||
@override
|
@override
|
||||||
final int typeId = 23;
|
final int typeId = 24;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AudienceTargetModel read(BinaryReader reader) {
|
AudienceTargetModel read(BinaryReader reader) {
|
||||||
|
|||||||
@@ -32,13 +32,16 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
|||||||
chkCopieMailRecu: fields[16] as bool?,
|
chkCopieMailRecu: fields[16] as bool?,
|
||||||
chkAcceptSms: fields[17] as bool?,
|
chkAcceptSms: fields[17] as bool?,
|
||||||
chkActive: fields[18] as bool?,
|
chkActive: fields[18] as bool?,
|
||||||
|
chkStripe: fields[19] as bool?,
|
||||||
|
createdAt: fields[20] as DateTime?,
|
||||||
|
updatedAt: fields[21] as DateTime?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void write(BinaryWriter writer, ClientModel obj) {
|
void write(BinaryWriter writer, ClientModel obj) {
|
||||||
writer
|
writer
|
||||||
..writeByte(19)
|
..writeByte(22)
|
||||||
..writeByte(0)
|
..writeByte(0)
|
||||||
..write(obj.id)
|
..write(obj.id)
|
||||||
..writeByte(1)
|
..writeByte(1)
|
||||||
@@ -76,7 +79,13 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
|||||||
..writeByte(17)
|
..writeByte(17)
|
||||||
..write(obj.chkAcceptSms)
|
..write(obj.chkAcceptSms)
|
||||||
..writeByte(18)
|
..writeByte(18)
|
||||||
..write(obj.chkActive);
|
..write(obj.chkActive)
|
||||||
|
..writeByte(19)
|
||||||
|
..write(obj.chkStripe)
|
||||||
|
..writeByte(20)
|
||||||
|
..write(obj.createdAt)
|
||||||
|
..writeByte(21)
|
||||||
|
..write(obj.updatedAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -14,48 +14,57 @@ class MembreModelAdapter extends TypeAdapter<MembreModel> {
|
|||||||
};
|
};
|
||||||
return MembreModel(
|
return MembreModel(
|
||||||
id: fields[0] as int,
|
id: fields[0] as int,
|
||||||
fkRole: fields[1] as int,
|
fkEntite: fields[1] as int?,
|
||||||
fkTitre: fields[2] as int,
|
role: fields[2] as int,
|
||||||
firstName: fields[3] as String,
|
fkTitre: fields[3] as int?,
|
||||||
sectName: fields[4] as String?,
|
name: fields[4] as String?,
|
||||||
dateNaissance: fields[5] as DateTime?,
|
firstName: fields[5] as String?,
|
||||||
dateEmbauche: fields[6] as DateTime?,
|
username: fields[6] as String?,
|
||||||
chkActive: fields[7] as int,
|
sectName: fields[7] as String?,
|
||||||
name: fields[8] as String,
|
email: fields[8] as String,
|
||||||
username: fields[9] as String,
|
phone: fields[9] as String?,
|
||||||
email: fields[10] as String,
|
mobile: fields[10] as String?,
|
||||||
fkEntite: fields[11] as int,
|
dateNaissance: fields[11] as DateTime?,
|
||||||
|
dateEmbauche: fields[12] as DateTime?,
|
||||||
|
createdAt: fields[13] as DateTime,
|
||||||
|
isActive: fields[14] as bool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void write(BinaryWriter writer, MembreModel obj) {
|
void write(BinaryWriter writer, MembreModel obj) {
|
||||||
writer
|
writer
|
||||||
..writeByte(12)
|
..writeByte(15)
|
||||||
..writeByte(0)
|
..writeByte(0)
|
||||||
..write(obj.id)
|
..write(obj.id)
|
||||||
..writeByte(1)
|
..writeByte(1)
|
||||||
..write(obj.fkRole)
|
..write(obj.fkEntite)
|
||||||
..writeByte(2)
|
..writeByte(2)
|
||||||
..write(obj.fkTitre)
|
..write(obj.role)
|
||||||
..writeByte(3)
|
..writeByte(3)
|
||||||
..write(obj.firstName)
|
..write(obj.fkTitre)
|
||||||
..writeByte(4)
|
..writeByte(4)
|
||||||
..write(obj.sectName)
|
|
||||||
..writeByte(5)
|
|
||||||
..write(obj.dateNaissance)
|
|
||||||
..writeByte(6)
|
|
||||||
..write(obj.dateEmbauche)
|
|
||||||
..writeByte(7)
|
|
||||||
..write(obj.chkActive)
|
|
||||||
..writeByte(8)
|
|
||||||
..write(obj.name)
|
..write(obj.name)
|
||||||
..writeByte(9)
|
..writeByte(5)
|
||||||
|
..write(obj.firstName)
|
||||||
|
..writeByte(6)
|
||||||
..write(obj.username)
|
..write(obj.username)
|
||||||
..writeByte(10)
|
..writeByte(7)
|
||||||
|
..write(obj.sectName)
|
||||||
|
..writeByte(8)
|
||||||
..write(obj.email)
|
..write(obj.email)
|
||||||
|
..writeByte(9)
|
||||||
|
..write(obj.phone)
|
||||||
|
..writeByte(10)
|
||||||
|
..write(obj.mobile)
|
||||||
..writeByte(11)
|
..writeByte(11)
|
||||||
..write(obj.fkEntite);
|
..write(obj.dateNaissance)
|
||||||
|
..writeByte(12)
|
||||||
|
..write(obj.dateEmbauche)
|
||||||
|
..writeByte(13)
|
||||||
|
..write(obj.createdAt)
|
||||||
|
..writeByte(14)
|
||||||
|
..write(obj.isActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
class UserSectorModelAdapter extends TypeAdapter<UserSectorModel> {
|
class UserSectorModelAdapter extends TypeAdapter<UserSectorModel> {
|
||||||
@override
|
@override
|
||||||
final int typeId = 7;
|
final int typeId = 6;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
UserSectorModel read(BinaryReader reader) {
|
UserSectorModel read(BinaryReader reader) {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
Extension Discovery Cache
|
|
||||||
=========================
|
|
||||||
|
|
||||||
This folder is used by `package:extension_discovery` to cache lists of
|
|
||||||
packages that contains extensions for other packages.
|
|
||||||
|
|
||||||
DO NOT USE THIS FOLDER
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
* Do not read (or rely) the contents of this folder.
|
|
||||||
* Do write to this folder.
|
|
||||||
|
|
||||||
If you're interested in the lists of extensions stored in this folder use the
|
|
||||||
API offered by package `extension_discovery` to get this information.
|
|
||||||
|
|
||||||
If this package doesn't work for your use-case, then don't try to read the
|
|
||||||
contents of this folder. It may change, and will not remain stable.
|
|
||||||
|
|
||||||
Use package `extension_discovery`
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
If you want to access information from this folder.
|
|
||||||
|
|
||||||
Feel free to delete this folder
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
Files in this folder act as a cache, and the cache is discarded if the files
|
|
||||||
are older than the modification time of `.dart_tool/package_config.json`.
|
|
||||||
|
|
||||||
Hence, it should never be necessary to clear this cache manually, if you find a
|
|
||||||
need to do please file a bug.
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"version":2,"entries":[{"package":"geosector_app","rootUri":"../","packageUri":"lib/"}]}
|
|
||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1780,6 +1780,10 @@ file:///Users/pierre/dev/geosector/app/lib/core/repositories/user_repository.dar
|
|||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/api_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/api_service.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/app_info_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/app_info_service.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/connectivity_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/connectivity_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/current_amicale_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/current_user_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/data_loading_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_adapters.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_reset_state_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_reset_state_service.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_web_fix.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_web_fix.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/location_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/location_service.dart
|
||||||
@@ -1823,7 +1827,6 @@ file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/custom_text_fiel
|
|||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_app_bar.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_app_bar.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_layout.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_layout.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/help_dialog.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/help_dialog.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/loading_overlay.dart
|
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/loading_progress_overlay.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/loading_progress_overlay.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/mapbox_map.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/mapbox_map.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/membre_row_widget.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/membre_row_widget.dart
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1779,6 +1779,10 @@ file:///Users/pierre/dev/geosector/app/lib/core/repositories/user_repository.dar
|
|||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/api_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/api_service.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/app_info_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/app_info_service.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/connectivity_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/connectivity_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/current_amicale_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/current_user_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/data_loading_service.dart
|
||||||
|
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_adapters.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_reset_state_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_reset_state_service.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_web_fix.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/hive_web_fix.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/core/services/location_service.dart
|
file:///Users/pierre/dev/geosector/app/lib/core/services/location_service.dart
|
||||||
@@ -1822,7 +1826,6 @@ file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/custom_text_fiel
|
|||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_app_bar.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_app_bar.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_layout.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/dashboard_layout.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/help_dialog.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/help_dialog.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/loading_overlay.dart
|
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/loading_progress_overlay.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/loading_progress_overlay.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/mapbox_map.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/mapbox_map.dart
|
||||||
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/membre_row_widget.dart
|
file:///Users/pierre/dev/geosector/app/lib/presentation/widgets/membre_row_widget.dart
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
210
app/PLAN2-APP.md
210
app/PLAN2-APP.md
@@ -29,9 +29,9 @@
|
|||||||
|
|
||||||
## 🚀 SESSION DE TRAVAIL - PLANNING DÉTAILLÉ
|
## 🚀 SESSION DE TRAVAIL - PLANNING DÉTAILLÉ
|
||||||
|
|
||||||
### Phase 0: Préparation Git et environnement (15 min)
|
### Phase 0: Préparation Git et environnement (15 min) ✅
|
||||||
|
|
||||||
#### Tâche 0.1: Création de la branche (5 min)
|
#### Tâche 0.1: Création de la branche (5 min) ✅
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Créer et basculer sur la nouvelle branche
|
# Créer et basculer sur la nouvelle branche
|
||||||
@@ -41,7 +41,7 @@ git checkout -b singletons
|
|||||||
git branch
|
git branch
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 0.2: Backup et documentation (10 min)
|
#### Tâche 0.2: Backup et documentation (10 min) ✅
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Créer un backup des fichiers critiques
|
# Créer un backup des fichiers critiques
|
||||||
@@ -72,9 +72,9 @@ git commit -m "feat: création branche singletons - début refactorisation
|
|||||||
- Objectif: renommer Box users -> user"
|
- Objectif: renommer Box users -> user"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Phase 1: Préparation et analyse (45 min)
|
### Phase 1: Préparation et analyse (45 min) ✅
|
||||||
|
|
||||||
#### Tâche 1.1: Audit du code existant (20 min)
|
#### Tâche 1.1: Audit du code existant (20 min) ✅
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Rechercher toutes les utilisations des services
|
# Rechercher toutes les utilisations des services
|
||||||
@@ -94,7 +94,7 @@ grep -r "usersBoxName" app/lib --include="*.dart" > audit_usersbox.txt
|
|||||||
- [x] Analyser les Box Hive users/amicale
|
- [x] Analyser les Box Hive users/amicale
|
||||||
- [x] Identifier toutes les occurrences de "usersBoxName"
|
- [x] Identifier toutes les occurrences de "usersBoxName"
|
||||||
|
|
||||||
#### Tâche 1.2: Modification app_keys.dart pour renommage Box (10 min)
|
#### Tâche 1.2: Modification app_keys.dart pour renommage Box (10 min) ✅
|
||||||
|
|
||||||
**Fichier à modifier** : `app/lib/core/constants/app_keys.dart`
|
**Fichier à modifier** : `app/lib/core/constants/app_keys.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
@@ -103,7 +103,7 @@ grep -r "usersBoxName" app/lib --include="*.dart" > audit_usersbox.txt
|
|||||||
- [x] Ajouter une constante de migration si nécessaire
|
- [x] Ajouter une constante de migration si nécessaire
|
||||||
- [x] Documenter le changement
|
- [x] Documenter le changement
|
||||||
|
|
||||||
**Code à modifier** :
|
**Code modifié** :
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
// Avant
|
// Avant
|
||||||
@@ -114,28 +114,83 @@ static const String userBoxName = 'user'; // Box pour l'utilisateur unique conne
|
|||||||
static const String usersBoxNameOld = 'users'; // Pour migration si nécessaire
|
static const String usersBoxNameOld = 'users'; // Pour migration si nécessaire
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 1.3: Planification de la refactorisation (15 min)
|
#### Tâche 1.3: Planification de la refactorisation (15 min) ✅
|
||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
- [ ] Créer une liste des repositories à modifier
|
- [x] Créer une liste des repositories à modifier
|
||||||
- [ ] Identifier les pages/widgets accédant aux données utilisateur
|
- [x] Identifier les pages/widgets accédant aux données utilisateur
|
||||||
- [ ] Planifier l'ordre de modification (dépendances)
|
- [x] Planifier l'ordre de modification (dépendances)
|
||||||
- [ ] Préparer la stratégie de tests
|
- [x] Préparer la stratégie de tests
|
||||||
- [ ] Définir l'architecture des nouveaux services
|
- [x] Définir l'architecture des nouveaux services
|
||||||
- [ ] Planifier la migration de la Box users -> user
|
- [x] Planifier la migration de la Box users -> user
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 2: Renommage et migration de la Hive Box (30 min)
|
### Phase 2: Correction des modèles et préparation (60 min) ✅
|
||||||
|
|
||||||
#### Tâche 2.1: Mise à jour main.dart pour la nouvelle Box (15 min)
|
#### Tâche 2.1: Correction MembreModel selon les vrais champs (30 min) ✅
|
||||||
|
|
||||||
|
**Fichier modifié** : `app/lib/core/data/models/membre_model.dart`
|
||||||
|
**Actions** :
|
||||||
|
|
||||||
|
- [x] Corriger les champs selon les spécifications réelles :
|
||||||
|
|
||||||
|
- `final int id`
|
||||||
|
- `int? fkEntite`
|
||||||
|
- `final int role`
|
||||||
|
- `int? fkTitre`
|
||||||
|
- `String? name`
|
||||||
|
- `String? firstName`
|
||||||
|
- `String? username`
|
||||||
|
- `String? sectName`
|
||||||
|
- `final String email`
|
||||||
|
- `String? phone`
|
||||||
|
- `String? mobile`
|
||||||
|
- `DateTime? dateNaissance`
|
||||||
|
- `DateTime? dateEmbauche`
|
||||||
|
- `final DateTime createdAt`
|
||||||
|
- `bool isActive`
|
||||||
|
|
||||||
|
- [x] Adapter les annotations Hive @HiveField
|
||||||
|
- [x] Corriger fromJson() et toJson()
|
||||||
|
- [x] Mettre à jour copyWith()
|
||||||
|
|
||||||
|
#### Tâche 2.2: Correction ClientModel avec champs manquants (15 min) ✅
|
||||||
|
|
||||||
|
**Fichier modifié** : `app/lib/core/data/models/client_model.dart`
|
||||||
|
**Actions** :
|
||||||
|
|
||||||
|
- [x] Ajouter les champs manqués : `chkStripe`, `createdAt`, `updatedAt`
|
||||||
|
- [x] Mettre à jour les annotations Hive
|
||||||
|
- [x] Corriger fromJson() et toJson()
|
||||||
|
- [x] Mettre à jour copyWith()
|
||||||
|
|
||||||
|
#### Tâche 2.3: Correction des repositories selon les vrais modèles (15 min) ✅
|
||||||
|
|
||||||
|
**Fichiers modifiés** :
|
||||||
|
|
||||||
|
- `app/lib/core/repositories/membre_repository.dart`
|
||||||
|
- `app/lib/core/repositories/client_repository.dart`
|
||||||
|
**Actions** :
|
||||||
|
|
||||||
|
- [x] Adapter MembreRepository pour les vrais champs (`isActive` au lieu de `chkActive`, etc.)
|
||||||
|
- [x] Corriger les méthodes create/update pour éviter les reconstructions manuelles
|
||||||
|
- [x] Utiliser copyWith() correctement
|
||||||
|
- [x] Simplifier la logique de création API
|
||||||
|
- [x] Corriger ClientRepository de la même manière
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 3: Renommage et migration de la Hive Box (30 min)
|
||||||
|
|
||||||
|
#### Tâche 3.1: Mise à jour main.dart pour la nouvelle Box (15 min)
|
||||||
|
|
||||||
**Fichier à modifier** : `app/lib/main.dart`
|
**Fichier à modifier** : `app/lib/main.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
- [x] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
- [ ] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||||
- [x] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
- [ ] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
||||||
- [ ] Ajouter logique de migration depuis l'ancienne Box si nécessaire
|
- [ ] Ajouter logique de migration depuis l'ancienne Box si nécessaire
|
||||||
|
|
||||||
**Code à modifier** :
|
**Code à modifier** :
|
||||||
@@ -171,18 +226,17 @@ Future<void> _openEssentialHiveBoxes() async {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('⚠️ Erreur migration box users: $e');
|
debugPrint('⚠️ Erreur migration box users: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 2.2: Mise à jour UserRepository pour la nouvelle Box (15 min)
|
#### Tâche 3.2: Mise à jour UserRepository pour la nouvelle Box (15 min)
|
||||||
|
|
||||||
**Fichier à modifier** : `app/lib/core/repositories/user_repository.dart`
|
**Fichier à modifier** : `app/lib/core/repositories/user_repository.dart`
|
||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
- [x] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
- [ ] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||||
- [x] Modifier les getters de Box
|
- [ ] Modifier les getters de Box
|
||||||
- [x] Tester que la compilation passe
|
- [ ] Tester que la compilation passe
|
||||||
|
|
||||||
**Code à modifier** :
|
**Code à modifier** :
|
||||||
|
|
||||||
@@ -196,16 +250,16 @@ Box<UserModel> get _userBox => Hive.box<UserModel>(AppKeys.userBoxName);
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 3: Création du nouveau ApiService Singleton (45 min)
|
### Phase 4: Création du nouveau ApiService Singleton (45 min)
|
||||||
|
|
||||||
#### Tâche 3.1: Backup du code existant (5 min)
|
#### Tâche 4.1: Backup du code existant (5 min)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Sauvegarder l'ApiService actuel
|
# Sauvegarder l'ApiService actuel
|
||||||
cp app/lib/core/services/api_service.dart app/lib/core/services/api_service_backup.dart
|
cp app/lib/core/services/api_service.dart app/lib/core/services/api_service_backup.dart
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 3.2: Refactorisation ApiService en Singleton (40 min)
|
#### Tâche 4.2: Refactorisation ApiService en Singleton (40 min)
|
||||||
|
|
||||||
**Fichier à modifier** : `app/lib/core/services/api_service.dart`
|
**Fichier à modifier** : `app/lib/core/services/api_service.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
@@ -287,9 +341,9 @@ class ApiService {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 4: Création des Services Singleton Utilisateur/Amicale (90 min)
|
### Phase 5: Création des Services Singleton Utilisateur/Amicale (90 min)
|
||||||
|
|
||||||
#### Tâche 4.1: Création CurrentUserService (45 min)
|
#### Tâche 5.1: Création CurrentUserService (45 min)
|
||||||
|
|
||||||
**Fichier à créer** : `app/lib/core/services/current_user_service.dart`
|
**Fichier à créer** : `app/lib/core/services/current_user_service.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
@@ -457,7 +511,7 @@ class CurrentUserService extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 4.2: Création CurrentAmicaleService (45 min)
|
#### Tâche 5.2: Création CurrentAmicaleService (45 min)
|
||||||
|
|
||||||
**Fichier à créer** : `app/lib/core/services/current_amicale_service.dart`
|
**Fichier à créer** : `app/lib/core/services/current_amicale_service.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
@@ -619,9 +673,9 @@ class CurrentAmicaleService extends ChangeNotifier {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 5: Modification du main.dart (20 min)
|
### Phase 6: Modification du main.dart (20 min)
|
||||||
|
|
||||||
#### Tâche 5.1: Intégration dans main.dart (20 min)
|
#### Tâche 6.1: Intégration dans main.dart (20 min)
|
||||||
|
|
||||||
**Fichier à modifier** : `app/lib/main.dart`
|
**Fichier à modifier** : `app/lib/main.dart`
|
||||||
**Actions** :
|
**Actions** :
|
||||||
@@ -668,9 +722,9 @@ import 'package:geosector_app/core/services/current_amicale_service.dart';
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 6: Commit intermédiaire de sécurité (10 min)
|
### Phase 7: Commit intermédiaire de sécurité (10 min)
|
||||||
|
|
||||||
#### Tâche 6.1: Commit des services créés (10 min)
|
#### Tâche 7.1: Commit des services créés (10 min)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ajouter tous les nouveaux fichiers
|
# Ajouter tous les nouveaux fichiers
|
||||||
@@ -704,9 +758,9 @@ Box Hive:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 7: Modification de l'App principale (20 min)
|
### Phase 8: Modification de l'App principale (20 min)
|
||||||
|
|
||||||
#### Tâche 7.1: Refactorisation app.dart (20 min)
|
#### Tâche 8.1: Refactorisation app.dart (20 min)
|
||||||
|
|
||||||
**Fichier à modifier** : `app/lib/app.dart`
|
**Fichier à modifier** : `app/lib/app.dart`
|
||||||
|
|
||||||
@@ -734,9 +788,9 @@ final userRepository = UserRepository(apiService);
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 8: Refactorisation des Repositories (90 min)
|
### Phase 9: Refactorisation des Repositories (90 min)
|
||||||
|
|
||||||
#### Tâche 8.1: UserRepository - Refactorisation majeure (40 min)
|
#### Tâche 9.1: UserRepository - Refactorisation majeure (40 min)
|
||||||
|
|
||||||
**Fichier** : `app/lib/core/repositories/user_repository.dart`
|
**Fichier** : `app/lib/core/repositories/user_repository.dart`
|
||||||
|
|
||||||
@@ -855,7 +909,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 8.2: AmicaleRepository (20 min)
|
#### Tâche 9.2: AmicaleRepository (20 min)
|
||||||
|
|
||||||
**Fichier** : `app/lib/core/repositories/amicale_repository.dart`
|
**Fichier** : `app/lib/core/repositories/amicale_repository.dart`
|
||||||
|
|
||||||
@@ -866,7 +920,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
- [ ] Simplifier l'accès à l'amicale courante
|
- [ ] Simplifier l'accès à l'amicale courante
|
||||||
- [ ] Intégrer avec CurrentAmicaleService
|
- [ ] Intégrer avec CurrentAmicaleService
|
||||||
|
|
||||||
#### Tâche 8.3: MembreRepository (15 min)
|
#### Tâche 9.3: MembreRepository (15 min)
|
||||||
|
|
||||||
**Fichier** : `app/lib/core/repositories/membre_repository.dart`
|
**Fichier** : `app/lib/core/repositories/membre_repository.dart`
|
||||||
|
|
||||||
@@ -876,7 +930,7 @@ class UserRepository extends ChangeNotifier {
|
|||||||
- [ ] Utiliser `ApiService.instance` dans les méthodes
|
- [ ] Utiliser `ApiService.instance` dans les méthodes
|
||||||
- [ ] Utiliser CurrentUserService pour les vérifications de permissions
|
- [ ] Utiliser CurrentUserService pour les vérifications de permissions
|
||||||
|
|
||||||
#### Tâche 8.4: Autres repositories (15 min)
|
#### Tâche 9.4: Autres repositories (15 min)
|
||||||
|
|
||||||
**Fichiers à traiter** :
|
**Fichiers à traiter** :
|
||||||
|
|
||||||
@@ -893,9 +947,9 @@ class UserRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 9: Modification des Pages principales (120 min)
|
### Phase 10: Modification des Pages principales (120 min)
|
||||||
|
|
||||||
#### Tâche 9.1: Pages d'authentification (30 min)
|
#### Tâche 10.1: Pages d'authentification (30 min)
|
||||||
|
|
||||||
**Fichiers** :
|
**Fichiers** :
|
||||||
|
|
||||||
@@ -954,7 +1008,7 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 9.2: Dashboard pages (30 min)
|
#### Tâche 10.2: Dashboard pages (30 min)
|
||||||
|
|
||||||
**Fichiers** :
|
**Fichiers** :
|
||||||
|
|
||||||
@@ -1041,7 +1095,7 @@ class AdminDashboardPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 9.3: Pages de gestion (30 min)
|
#### Tâche 10.3: Pages de gestion (30 min)
|
||||||
|
|
||||||
**Fichiers** :
|
**Fichiers** :
|
||||||
|
|
||||||
@@ -1055,7 +1109,7 @@ class AdminDashboardPage extends StatelessWidget {
|
|||||||
- [ ] Utiliser les services singleton
|
- [ ] Utiliser les services singleton
|
||||||
- [ ] Simplifier l'accès aux données
|
- [ ] Simplifier l'accès aux données
|
||||||
|
|
||||||
#### Tâche 9.4: Pages formulaires (30 min)
|
#### Tâche 10.4: Pages formulaires (30 min)
|
||||||
|
|
||||||
**Fichiers contenant des formulaires** :
|
**Fichiers contenant des formulaires** :
|
||||||
|
|
||||||
@@ -1071,9 +1125,9 @@ class AdminDashboardPage extends StatelessWidget {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 10: Modification des Widgets (90 min)
|
### Phase 11: Modification des Widgets (90 min)
|
||||||
|
|
||||||
#### Tâche 10.1: Création de widgets d'information (30 min)
|
#### Tâche 11.1: Création de widgets d'information (30 min)
|
||||||
|
|
||||||
**Nouveaux widgets à créer** :
|
**Nouveaux widgets à créer** :
|
||||||
|
|
||||||
@@ -1209,7 +1263,7 @@ class AmicaleInfoWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 10.2: Widgets de tableaux (30 min)
|
#### Tâche 11.2: Widgets de tableaux (30 min)
|
||||||
|
|
||||||
**Fichiers** :
|
**Fichiers** :
|
||||||
|
|
||||||
@@ -1223,7 +1277,7 @@ class AmicaleInfoWidget extends StatelessWidget {
|
|||||||
- [ ] Utiliser CurrentUserService pour les vérifications de permissions
|
- [ ] Utiliser CurrentUserService pour les vérifications de permissions
|
||||||
- [ ] Simplifier la logique d'affichage conditionnel
|
- [ ] Simplifier la logique d'affichage conditionnel
|
||||||
|
|
||||||
#### Tâche 10.3: Widgets de formulaires (30 min)
|
#### Tâche 11.3: Widgets de formulaires (30 min)
|
||||||
|
|
||||||
**Fichiers** :
|
**Fichiers** :
|
||||||
|
|
||||||
@@ -1238,9 +1292,9 @@ class AmicaleInfoWidget extends StatelessWidget {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 11: Mise à jour du Router et Navigation (45 min)
|
### Phase 12: Mise à jour du Router et Navigation (45 min)
|
||||||
|
|
||||||
#### Tâche 11.1: Configuration GoRouter (30 min)
|
#### Tâche 12.1: Configuration GoRouter (30 min)
|
||||||
|
|
||||||
**Fichier** : `app/lib/core/routing/app_router.dart`
|
**Fichier** : `app/lib/core/routing/app_router.dart`
|
||||||
|
|
||||||
@@ -1275,7 +1329,7 @@ GoRoute(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 11.2: Création AuthGuard (15 min)
|
#### Tâche 12.2: Création AuthGuard (15 min)
|
||||||
|
|
||||||
**Fichier à créer** : `app/lib/core/routing/auth_guard.dart`
|
**Fichier à créer** : `app/lib/core/routing/auth_guard.dart`
|
||||||
|
|
||||||
@@ -1327,9 +1381,9 @@ class AuthGuard {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 12: Tests et validation (60 min)
|
### Phase 13: Tests et validation (60 min)
|
||||||
|
|
||||||
#### Tâche 12.1: Tests de compilation (15 min)
|
#### Tâche 13.1: Tests de compilation (15 min)
|
||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
@@ -1338,7 +1392,7 @@ class AuthGuard {
|
|||||||
- [ ] Corriger erreurs de compilation
|
- [ ] Corriger erreurs de compilation
|
||||||
- [ ] Vérifier warnings
|
- [ ] Vérifier warnings
|
||||||
|
|
||||||
#### Tâche 12.2: Tests fonctionnels de base (30 min)
|
#### Tâche 13.2: Tests fonctionnels de base (30 min)
|
||||||
|
|
||||||
**Scénarios à tester** :
|
**Scénarios à tester** :
|
||||||
|
|
||||||
@@ -1350,7 +1404,7 @@ class AuthGuard {
|
|||||||
- [ ] Persistence des données au redémarrage
|
- [ ] Persistence des données au redémarrage
|
||||||
- [ ] Migration de la Box users -> user
|
- [ ] Migration de la Box users -> user
|
||||||
|
|
||||||
#### Tâche 12.3: Tests des services singleton (15 min)
|
#### Tâche 13.3: Tests des services singleton (15 min)
|
||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
@@ -1361,9 +1415,9 @@ class AuthGuard {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 13: Tests unitaires (45 min)
|
### Phase 14: Tests unitaires (45 min)
|
||||||
|
|
||||||
#### Tâche 13.1: Tests ApiService (15 min)
|
#### Tâche 14.1: Tests ApiService (15 min)
|
||||||
|
|
||||||
**Fichier** : `test/core/services/api_service_test.dart`
|
**Fichier** : `test/core/services/api_service_test.dart`
|
||||||
|
|
||||||
@@ -1374,7 +1428,7 @@ class AuthGuard {
|
|||||||
- [ ] Tester thread-safety
|
- [ ] Tester thread-safety
|
||||||
- [ ] Mocker les appels réseau
|
- [ ] Mocker les appels réseau
|
||||||
|
|
||||||
#### Tâche 13.2: Tests CurrentUserService (15 min)
|
#### Tâche 14.2: Tests CurrentUserService (15 min)
|
||||||
|
|
||||||
**Fichier** : `test/core/services/current_user_service_test.dart`
|
**Fichier** : `test/core/services/current_user_service_test.dart`
|
||||||
|
|
||||||
@@ -1385,7 +1439,7 @@ class AuthGuard {
|
|||||||
- [ ] Tester persistence Hive avec nouvelle Box
|
- [ ] Tester persistence Hive avec nouvelle Box
|
||||||
- [ ] Tester les getters de rôles
|
- [ ] Tester les getters de rôles
|
||||||
|
|
||||||
#### Tâche 13.3: Tests CurrentAmicaleService (15 min)
|
#### Tâche 14.3: Tests CurrentAmicaleService (15 min)
|
||||||
|
|
||||||
**Fichier** : `test/core/services/current_amicale_service_test.dart`
|
**Fichier** : `test/core/services/current_amicale_service_test.dart`
|
||||||
|
|
||||||
@@ -1398,9 +1452,9 @@ class AuthGuard {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 14: Optimisations et nettoyage (45 min)
|
### Phase 15: Optimisations et nettoyage (45 min)
|
||||||
|
|
||||||
#### Tâche 14.1: Optimisation des performances (20 min)
|
#### Tâche 15.1: Optimisation des performances (20 min)
|
||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
@@ -1409,7 +1463,7 @@ class AuthGuard {
|
|||||||
- [ ] Éliminer les rebuilds inutiles
|
- [ ] Éliminer les rebuilds inutiles
|
||||||
- [ ] Vérifier les memory leaks
|
- [ ] Vérifier les memory leaks
|
||||||
|
|
||||||
#### Tâche 14.2: Nettoyage du code (25 min)
|
#### Tâche 15.2: Nettoyage du code (25 min)
|
||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
@@ -1421,9 +1475,9 @@ class AuthGuard {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 15: Commit final et documentation (30 min)
|
### Phase 16: Commit final et documentation (30 min)
|
||||||
|
|
||||||
#### Tâche 15.1: Commit final (15 min)
|
#### Tâche 16.1: Commit final (15 min)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ajouter tous les fichiers modifiés
|
# Ajouter tous les fichiers modifiés
|
||||||
@@ -1447,8 +1501,15 @@ Hive Box:
|
|||||||
Repositories:
|
Repositories:
|
||||||
✅ UserRepository simplifié (plus d'injection ApiService)
|
✅ UserRepository simplifié (plus d'injection ApiService)
|
||||||
✅ AmicaleRepository simplifié
|
✅ AmicaleRepository simplifié
|
||||||
|
✅ MembreRepository corrigé selon vrais champs modèle
|
||||||
|
✅ ClientRepository corrigé selon vrais champs modèle
|
||||||
✅ Tous les repositories utilisent ApiService.instance
|
✅ Tous les repositories utilisent ApiService.instance
|
||||||
|
|
||||||
|
Models:
|
||||||
|
✅ MembreModel corrigé avec les vrais champs
|
||||||
|
✅ ClientModel complété avec champs manquants
|
||||||
|
✅ Méthodes create/update simplifiées dans repositories
|
||||||
|
|
||||||
UI/UX:
|
UI/UX:
|
||||||
✅ Pages sans injections de dépendances
|
✅ Pages sans injections de dépendances
|
||||||
✅ Widgets UserInfoWidget et AmicaleInfoWidget réactifs
|
✅ Widgets UserInfoWidget et AmicaleInfoWidget réactifs
|
||||||
@@ -1468,6 +1529,7 @@ BREAKING CHANGES:
|
|||||||
- Box Hive users renommée en user
|
- Box Hive users renommée en user
|
||||||
- Constructeurs de pages/widgets simplifiés
|
- Constructeurs de pages/widgets simplifiés
|
||||||
- Pattern d'accès aux données utilisateur/amicale changé
|
- Pattern d'accès aux données utilisateur/amicale changé
|
||||||
|
- Champs de modèles corrigés selon spécifications
|
||||||
|
|
||||||
MIGRATION: Automatique au démarrage de l'app"
|
MIGRATION: Automatique au démarrage de l'app"
|
||||||
|
|
||||||
@@ -1475,7 +1537,7 @@ MIGRATION: Automatique au démarrage de l'app"
|
|||||||
git push origin singletons
|
git push origin singletons
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Tâche 15.2: Documentation finale (15 min)
|
#### Tâche 16.2: Documentation finale (15 min)
|
||||||
|
|
||||||
**Actions** :
|
**Actions** :
|
||||||
|
|
||||||
@@ -1523,15 +1585,29 @@ final hasGps = CurrentAmicaleService.instance.hasGpsCoordinates;
|
|||||||
final response = await ApiService.instance.get('/endpoint');
|
final response = await ApiService.instance.get('/endpoint');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Corrections modèles
|
||||||
|
|
||||||
|
### MembreModel
|
||||||
|
|
||||||
|
- Corrigé selon les vrais champs : `isActive`, `role`, etc.
|
||||||
|
- Plus de champs inventés
|
||||||
|
|
||||||
|
### ClientModel
|
||||||
|
|
||||||
|
- Ajout champs manquants : `chkStripe`, `createdAt`, `updatedAt`
|
||||||
|
|
||||||
## Migration
|
## Migration
|
||||||
|
|
||||||
- Box `users` renommée en `user` (migration automatique)
|
- Box `users` renommée en `user` (migration automatique)
|
||||||
- Plus d'injection de dépendances dans les constructeurs
|
- Plus d'injection de dépendances dans les constructeurs
|
||||||
- Widgets réactifs avec ListenableBuilder
|
- Widgets réactifs avec ListenableBuilder
|
||||||
|
- Repositories simplifiés
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📁 Structure finale des fichiers modifiés/créés
|
## 📁 Structure finale des fichiers modifiés/créés
|
||||||
|
|
||||||
|
### ✅ Fichiers déjà traités
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ GEOSECTOR est une application Flutter qui permet aux amicales de pompiers de gé
|
|||||||
- **Framework** : Flutter 3.32
|
- **Framework** : Flutter 3.32
|
||||||
- **Routing** : Go Router
|
- **Routing** : Go Router
|
||||||
- **Base de données locale** : Hive
|
- **Base de données locale** : Hive
|
||||||
- **Gestion d'état** : Provider + Repository Pattern
|
- **Gestion d'état** : Repository Pattern (Pas de Provider, Get.It, etc...)
|
||||||
- **Cartes** : Flutter Map avec Mapbox
|
- **Cartes** : Flutter Map avec Mapbox
|
||||||
- **API** : Dio pour les requêtes HTTP
|
- **API** : Dio pour les requêtes HTTP
|
||||||
- **Chat** : MQTT5 Client
|
- **Chat** : MQTT5 Client
|
||||||
@@ -35,8 +35,6 @@ L'application utilise une architecture en couches pour la gestion des données :
|
|||||||
```
|
```
|
||||||
UI Layer (Widgets)
|
UI Layer (Widgets)
|
||||||
↓
|
↓
|
||||||
Provider Layer (State Management)
|
|
||||||
↓
|
|
||||||
Repository Layer (Business Logic)
|
Repository Layer (Business Logic)
|
||||||
↓
|
↓
|
||||||
Data Layer (Hive + API)
|
Data Layer (Hive + API)
|
||||||
@@ -45,9 +43,8 @@ Data Layer (Hive + API)
|
|||||||
#### Couches de l'architecture
|
#### Couches de l'architecture
|
||||||
|
|
||||||
1. **UI Layer** : Widgets Flutter qui affichent les données
|
1. **UI Layer** : Widgets Flutter qui affichent les données
|
||||||
2. **Provider Layer** : Gestion d'état avec ChangeNotifier
|
2. **Repository Layer** : Logique métier et orchestration des sources de données
|
||||||
3. **Repository Layer** : Logique métier et orchestration des sources de données
|
3. **Data Layer** : Stockage local (Hive) et API distante
|
||||||
4. **Data Layer** : Stockage local (Hive) et API distante
|
|
||||||
|
|
||||||
### Structure des dossiers
|
### Structure des dossiers
|
||||||
|
|
||||||
@@ -87,12 +84,14 @@ lib/
|
|||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
1. **Cloner le repository**
|
1. **Cloner le repository**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/votre-repo/geosector.git
|
git clone https://github.com/votre-repo/geosector.git
|
||||||
cd geosector
|
cd geosector
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Installer les dépendances**
|
2. **Installer les dépendances**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
flutter pub get
|
flutter pub get
|
||||||
```
|
```
|
||||||
@@ -100,6 +99,7 @@ lib/
|
|||||||
3. **Configuration des clés API**
|
3. **Configuration des clés API**
|
||||||
|
|
||||||
Créer un fichier `.env` à la racine :
|
Créer un fichier `.env` à la racine :
|
||||||
|
|
||||||
```env
|
```env
|
||||||
MAPBOX_ACCESS_TOKEN=your_mapbox_token
|
MAPBOX_ACCESS_TOKEN=your_mapbox_token
|
||||||
API_BASE_URL=https://your-api.com
|
API_BASE_URL=https://your-api.com
|
||||||
@@ -119,7 +119,6 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# État et navigation
|
# État et navigation
|
||||||
provider: ^6.1.1
|
|
||||||
go_router: ^12.1.3
|
go_router: ^12.1.3
|
||||||
|
|
||||||
# Stockage local
|
# Stockage local
|
||||||
@@ -147,116 +146,53 @@ dev_dependencies:
|
|||||||
|
|
||||||
## 🗄️ Modèles de données
|
## 🗄️ Modèles de données
|
||||||
|
|
||||||
### Secteur
|
if (!Hive.isAdapterRegistered(0)) {
|
||||||
|
Hive.registerAdapter(UserModelAdapter());
|
||||||
```dart
|
|
||||||
@HiveType(typeId: 0)
|
|
||||||
class Secteur extends HiveObject {
|
|
||||||
@HiveField(0)
|
|
||||||
String id;
|
|
||||||
|
|
||||||
@HiveField(1)
|
|
||||||
String nom;
|
|
||||||
|
|
||||||
@HiveField(2)
|
|
||||||
List<LatLng> polygone;
|
|
||||||
|
|
||||||
@HiveField(3)
|
|
||||||
String couleur;
|
|
||||||
|
|
||||||
@HiveField(4)
|
|
||||||
int nombreCalendriers;
|
|
||||||
|
|
||||||
@HiveField(5)
|
|
||||||
DateTime dateCreation;
|
|
||||||
}
|
}
|
||||||
```
|
if (!Hive.isAdapterRegistered(1)) {
|
||||||
|
Hive.registerAdapter(OperationModelAdapter());
|
||||||
### Passage
|
|
||||||
|
|
||||||
```dart
|
|
||||||
@HiveType(typeId: 1)
|
|
||||||
class Passage extends HiveObject {
|
|
||||||
@HiveField(0)
|
|
||||||
String id;
|
|
||||||
|
|
||||||
@HiveField(1)
|
|
||||||
String secteurId;
|
|
||||||
|
|
||||||
@HiveField(2)
|
|
||||||
String utilisateurId;
|
|
||||||
|
|
||||||
@HiveField(3)
|
|
||||||
DateTime datePassage;
|
|
||||||
|
|
||||||
@HiveField(4)
|
|
||||||
LatLng position;
|
|
||||||
|
|
||||||
@HiveField(5)
|
|
||||||
int calendriersDistribues;
|
|
||||||
|
|
||||||
@HiveField(6)
|
|
||||||
String commentaire;
|
|
||||||
|
|
||||||
@HiveField(7)
|
|
||||||
List<String> photos;
|
|
||||||
}
|
}
|
||||||
```
|
if (!Hive.isAdapterRegistered(3)) {
|
||||||
|
Hive.registerAdapter(SectorModelAdapter());
|
||||||
### Utilisateur
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(4)) {
|
||||||
```dart
|
Hive.registerAdapter(PassageModelAdapter());
|
||||||
@HiveType(typeId: 2)
|
}
|
||||||
class Utilisateur extends HiveObject {
|
if (!Hive.isAdapterRegistered(5)) {
|
||||||
@HiveField(0)
|
Hive.registerAdapter(MembreModelAdapter());
|
||||||
String id;
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(6)) {
|
||||||
@HiveField(1)
|
Hive.registerAdapter(UserSectorModelAdapter());
|
||||||
String nom;
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(7)) {
|
||||||
@HiveField(2)
|
Hive.registerAdapter(RegionModelAdapter());
|
||||||
String email;
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(10)) {
|
||||||
@HiveField(3)
|
Hive.registerAdapter(ClientModelAdapter());
|
||||||
String role; // 'admin' ou 'user'
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(11)) {
|
||||||
@HiveField(4)
|
Hive.registerAdapter(AmicaleModelAdapter());
|
||||||
List<String> secteursAssignes;
|
|
||||||
|
|
||||||
@HiveField(5)
|
|
||||||
DateTime dernierLogin;
|
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 Gestion d'état avec Provider
|
// Chat adapters
|
||||||
|
if (!Hive.isAdapterRegistered(20)) {
|
||||||
### SecteurProvider
|
Hive.registerAdapter(ConversationModelAdapter());
|
||||||
|
|
||||||
```dart
|
|
||||||
class SecteurProvider extends ChangeNotifier {
|
|
||||||
final SecteurRepository _repository;
|
|
||||||
|
|
||||||
List<Secteur> _secteurs = [];
|
|
||||||
bool _isLoading = false;
|
|
||||||
|
|
||||||
List<Secteur> get secteurs => _secteurs;
|
|
||||||
bool get isLoading => _isLoading;
|
|
||||||
|
|
||||||
Future<void> loadSecteurs() async {
|
|
||||||
_isLoading = true;
|
|
||||||
notifyListeners();
|
|
||||||
|
|
||||||
try {
|
|
||||||
_secteurs = await _repository.getAllSecteurs();
|
|
||||||
} catch (e) {
|
|
||||||
// Gestion d'erreur
|
|
||||||
} finally {
|
|
||||||
_isLoading = false;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(21)) {
|
||||||
|
Hive.registerAdapter(MessageModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(22)) {
|
||||||
|
Hive.registerAdapter(ParticipantModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(23)) {
|
||||||
|
Hive.registerAdapter(AnonymousUserModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(24)) {
|
||||||
|
Hive.registerAdapter(AudienceTargetModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(25)) {
|
||||||
|
Hive.registerAdapter(NotificationSettingsAdapter());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🗺️ Cartes et géolocalisation
|
## 🗺️ Cartes et géolocalisation
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
{"guid":"dc4b70c03e8043e50e38f2068887b1d4","name":"Pods","path":"/Users/pierre/dev/geosector/app/ios/Pods/Pods.xcodeproj/project.xcworkspace","projects":["PROJECT@v11_mod=9c247933552af22255bf791d596f2dce_hash=bfdfe7dc352907fc980b868725387e98plugins=1OJSG6M1FOV3XYQCBH7Z29RZ0FPR9XDE1"]}
|
{"guid":"dc4b70c03e8043e50e38f2068887b1d4","name":"Pods","path":"/Users/pierre/dev/geosector/app/ios/Pods/Pods.xcodeproj/project.xcworkspace","projects":["PROJECT@v11_mod=0987d131841f12618fa22c05d7871702_hash=bfdfe7dc352907fc980b868725387e98plugins=1OJSG6M1FOV3XYQCBH7Z29RZ0FPR9XDE1"]}
|
||||||
@@ -39,6 +39,6 @@ _flutter.buildConfig = {"engineRevision":"1425e5e9ec5eeb4f225c401d8db69b860e0fde
|
|||||||
|
|
||||||
_flutter.loader.load({
|
_flutter.loader.load({
|
||||||
serviceWorkerSettings: {
|
serviceWorkerSettings: {
|
||||||
serviceWorkerVersion: "3087561979"
|
serviceWorkerVersion: "3209567515"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ const MANIFEST = 'flutter-app-manifest';
|
|||||||
const TEMP = 'flutter-temp-cache';
|
const TEMP = 'flutter-temp-cache';
|
||||||
const CACHE_NAME = 'flutter-app-cache';
|
const CACHE_NAME = 'flutter-app-cache';
|
||||||
|
|
||||||
const RESOURCES = {"flutter_bootstrap.js": "1dbbc20d0a6216228635de38eb5222a5",
|
const RESOURCES = {"flutter_bootstrap.js": "dbeddb5a67a21614f83df7c02ea4f54e",
|
||||||
"version.json": "727f6f584c125faac83c6d2a4c96fb3d",
|
"version.json": "727f6f584c125faac83c6d2a4c96fb3d",
|
||||||
"index.html": "2aab03d10fea3b608e3eddc0fc0077e5",
|
"index.html": "2aab03d10fea3b608e3eddc0fc0077e5",
|
||||||
"/": "2aab03d10fea3b608e3eddc0fc0077e5",
|
"/": "2aab03d10fea3b608e3eddc0fc0077e5",
|
||||||
"favicon-64.png": "259540a3217e969237530444ca0eaed3",
|
"favicon-64.png": "259540a3217e969237530444ca0eaed3",
|
||||||
"favicon-16.png": "106142fb24eba190e475dbe6513cc9ff",
|
"favicon-16.png": "106142fb24eba190e475dbe6513cc9ff",
|
||||||
"main.dart.js": "7530a148b4d52ca92f4706f660f16907",
|
"main.dart.js": "50fc919ba8d82c79ce420d777c0230eb",
|
||||||
"flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
|
"flutter.js": "83d881c1dbb6d6bcd6b42e274605b69c",
|
||||||
"favicon.png": "21510778ead066ac826ad69302400773",
|
"favicon.png": "21510778ead066ac826ad69302400773",
|
||||||
"icons/Icon-192.png": "f36879dd176101fac324b68793e4683c",
|
"icons/Icon-192.png": "f36879dd176101fac324b68793e4683c",
|
||||||
|
|||||||
140385
app/build/web/main.dart.js
140385
app/build/web/main.dart.js
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@ part 'anonymous_user_model.g.dart';
|
|||||||
/// Ce modèle représente un utilisateur anonyme (pour le cas Resalice)
|
/// Ce modèle représente un utilisateur anonyme (pour le cas Resalice)
|
||||||
/// et permet de tracker sa conversion éventuelle en utilisateur authentifié
|
/// et permet de tracker sa conversion éventuelle en utilisateur authentifié
|
||||||
|
|
||||||
@HiveType(typeId: 24)
|
@HiveType(typeId: 23)
|
||||||
class AnonymousUserModel extends HiveObject with EquatableMixin {
|
class AnonymousUserModel extends HiveObject with EquatableMixin {
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
final String id;
|
final String id;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ part of 'anonymous_user_model.dart';
|
|||||||
|
|
||||||
class AnonymousUserModelAdapter extends TypeAdapter<AnonymousUserModel> {
|
class AnonymousUserModelAdapter extends TypeAdapter<AnonymousUserModel> {
|
||||||
@override
|
@override
|
||||||
final int typeId = 24;
|
final int typeId = 23;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AnonymousUserModel read(BinaryReader reader) {
|
AnonymousUserModel read(BinaryReader reader) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ part 'audience_target_model.g.dart';
|
|||||||
/// Ce modèle représente une cible d'audience pour les annonces et broadcasts
|
/// Ce modèle représente une cible d'audience pour les annonces et broadcasts
|
||||||
/// Il supporte maintenant le ciblage combiné avec les filtres de rôle et d'entité
|
/// Il supporte maintenant le ciblage combiné avec les filtres de rôle et d'entité
|
||||||
|
|
||||||
@HiveType(typeId: 23)
|
@HiveType(typeId: 24)
|
||||||
class AudienceTargetModel extends HiveObject with EquatableMixin {
|
class AudienceTargetModel extends HiveObject with EquatableMixin {
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
final String id;
|
final String id;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ part of 'audience_target_model.dart';
|
|||||||
|
|
||||||
class AudienceTargetModelAdapter extends TypeAdapter<AudienceTargetModel> {
|
class AudienceTargetModelAdapter extends TypeAdapter<AudienceTargetModel> {
|
||||||
@override
|
@override
|
||||||
final int typeId = 23;
|
final int typeId = 24;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AudienceTargetModel read(BinaryReader reader) {
|
AudienceTargetModel read(BinaryReader reader) {
|
||||||
|
|||||||
@@ -61,6 +61,15 @@ class ClientModel extends HiveObject {
|
|||||||
@HiveField(18)
|
@HiveField(18)
|
||||||
final bool? chkActive;
|
final bool? chkActive;
|
||||||
|
|
||||||
|
@HiveField(19)
|
||||||
|
final bool? chkStripe;
|
||||||
|
|
||||||
|
@HiveField(20)
|
||||||
|
final DateTime? createdAt;
|
||||||
|
|
||||||
|
@HiveField(21)
|
||||||
|
final DateTime? updatedAt;
|
||||||
|
|
||||||
ClientModel({
|
ClientModel({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
@@ -81,6 +90,9 @@ class ClientModel extends HiveObject {
|
|||||||
this.chkCopieMailRecu,
|
this.chkCopieMailRecu,
|
||||||
this.chkAcceptSms,
|
this.chkAcceptSms,
|
||||||
this.chkActive,
|
this.chkActive,
|
||||||
|
this.chkStripe,
|
||||||
|
this.createdAt,
|
||||||
|
this.updatedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Factory pour convertir depuis JSON (API)
|
// Factory pour convertir depuis JSON (API)
|
||||||
@@ -93,8 +105,7 @@ class ClientModel extends HiveObject {
|
|||||||
int? fkRegion;
|
int? fkRegion;
|
||||||
if (json['fk_region'] != null) {
|
if (json['fk_region'] != null) {
|
||||||
final dynamic rawFkRegion = json['fk_region'];
|
final dynamic rawFkRegion = json['fk_region'];
|
||||||
fkRegion =
|
fkRegion = rawFkRegion is String ? int.parse(rawFkRegion) : rawFkRegion as int;
|
||||||
rawFkRegion is String ? int.parse(rawFkRegion) : rawFkRegion as int;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convertir fk_type en int si présent
|
// Convertir fk_type en int si présent
|
||||||
@@ -121,11 +132,12 @@ class ClientModel extends HiveObject {
|
|||||||
gpsLng: json['gps_lng'],
|
gpsLng: json['gps_lng'],
|
||||||
stripeId: json['stripe_id'],
|
stripeId: json['stripe_id'],
|
||||||
chkDemo: json['chk_demo'] == 1 || json['chk_demo'] == true,
|
chkDemo: json['chk_demo'] == 1 || json['chk_demo'] == true,
|
||||||
chkCopieMailRecu: json['chk_copie_mail_recu'] == 1 ||
|
chkCopieMailRecu: json['chk_copie_mail_recu'] == 1 || json['chk_copie_mail_recu'] == true,
|
||||||
json['chk_copie_mail_recu'] == true,
|
chkAcceptSms: json['chk_accept_sms'] == 1 || json['chk_accept_sms'] == true,
|
||||||
chkAcceptSms:
|
|
||||||
json['chk_accept_sms'] == 1 || json['chk_accept_sms'] == true,
|
|
||||||
chkActive: json['chk_active'] == 1 || json['chk_active'] == true,
|
chkActive: json['chk_active'] == 1 || json['chk_active'] == true,
|
||||||
|
chkStripe: json['chk_stripe'] == 1 || json['chk_stripe'] == true,
|
||||||
|
createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : null,
|
||||||
|
updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +163,9 @@ class ClientModel extends HiveObject {
|
|||||||
'chk_copie_mail_recu': chkCopieMailRecu,
|
'chk_copie_mail_recu': chkCopieMailRecu,
|
||||||
'chk_accept_sms': chkAcceptSms,
|
'chk_accept_sms': chkAcceptSms,
|
||||||
'chk_active': chkActive,
|
'chk_active': chkActive,
|
||||||
|
'chk_stripe': chkStripe,
|
||||||
|
'created_at': createdAt?.toIso8601String(),
|
||||||
|
'updated_at': updatedAt?.toIso8601String(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,9 +189,12 @@ class ClientModel extends HiveObject {
|
|||||||
bool? chkCopieMailRecu,
|
bool? chkCopieMailRecu,
|
||||||
bool? chkAcceptSms,
|
bool? chkAcceptSms,
|
||||||
bool? chkActive,
|
bool? chkActive,
|
||||||
|
bool? chkStripe,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
}) {
|
}) {
|
||||||
return ClientModel(
|
return ClientModel(
|
||||||
id: this.id,
|
id: id,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
adresse1: adresse1 ?? this.adresse1,
|
adresse1: adresse1 ?? this.adresse1,
|
||||||
adresse2: adresse2 ?? this.adresse2,
|
adresse2: adresse2 ?? this.adresse2,
|
||||||
@@ -195,6 +213,9 @@ class ClientModel extends HiveObject {
|
|||||||
chkCopieMailRecu: chkCopieMailRecu ?? this.chkCopieMailRecu,
|
chkCopieMailRecu: chkCopieMailRecu ?? this.chkCopieMailRecu,
|
||||||
chkAcceptSms: chkAcceptSms ?? this.chkAcceptSms,
|
chkAcceptSms: chkAcceptSms ?? this.chkAcceptSms,
|
||||||
chkActive: chkActive ?? this.chkActive,
|
chkActive: chkActive ?? this.chkActive,
|
||||||
|
chkStripe: chkStripe ?? this.chkStripe,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,13 +36,16 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
|||||||
chkCopieMailRecu: fields[16] as bool?,
|
chkCopieMailRecu: fields[16] as bool?,
|
||||||
chkAcceptSms: fields[17] as bool?,
|
chkAcceptSms: fields[17] as bool?,
|
||||||
chkActive: fields[18] as bool?,
|
chkActive: fields[18] as bool?,
|
||||||
|
chkStripe: fields[19] as bool?,
|
||||||
|
createdAt: fields[20] as DateTime?,
|
||||||
|
updatedAt: fields[21] as DateTime?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void write(BinaryWriter writer, ClientModel obj) {
|
void write(BinaryWriter writer, ClientModel obj) {
|
||||||
writer
|
writer
|
||||||
..writeByte(19)
|
..writeByte(22)
|
||||||
..writeByte(0)
|
..writeByte(0)
|
||||||
..write(obj.id)
|
..write(obj.id)
|
||||||
..writeByte(1)
|
..writeByte(1)
|
||||||
@@ -80,7 +83,13 @@ class ClientModelAdapter extends TypeAdapter<ClientModel> {
|
|||||||
..writeByte(17)
|
..writeByte(17)
|
||||||
..write(obj.chkAcceptSms)
|
..write(obj.chkAcceptSms)
|
||||||
..writeByte(18)
|
..writeByte(18)
|
||||||
..write(obj.chkActive);
|
..write(obj.chkActive)
|
||||||
|
..writeByte(19)
|
||||||
|
..write(obj.chkStripe)
|
||||||
|
..writeByte(20)
|
||||||
|
..write(obj.createdAt)
|
||||||
|
..writeByte(21)
|
||||||
|
..write(obj.updatedAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -8,51 +8,53 @@ class MembreModel extends HiveObject {
|
|||||||
final int id;
|
final int id;
|
||||||
|
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
final int fkRole;
|
int? fkEntite;
|
||||||
|
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
final int fkTitre;
|
final int role;
|
||||||
|
|
||||||
@HiveField(3)
|
@HiveField(3)
|
||||||
final String firstName;
|
int? fkTitre;
|
||||||
|
|
||||||
@HiveField(4)
|
@HiveField(4)
|
||||||
final String? sectName;
|
String? name;
|
||||||
|
|
||||||
@HiveField(5)
|
@HiveField(5)
|
||||||
final DateTime? dateNaissance;
|
String? firstName;
|
||||||
|
|
||||||
@HiveField(6)
|
@HiveField(6)
|
||||||
final DateTime? dateEmbauche;
|
String? username;
|
||||||
|
|
||||||
@HiveField(7)
|
@HiveField(7)
|
||||||
final int chkActive;
|
String? sectName;
|
||||||
|
|
||||||
@HiveField(8)
|
@HiveField(8)
|
||||||
final String name;
|
|
||||||
|
|
||||||
@HiveField(9)
|
|
||||||
final String username;
|
|
||||||
|
|
||||||
@HiveField(10)
|
|
||||||
final String email;
|
final String email;
|
||||||
|
|
||||||
|
@HiveField(9)
|
||||||
|
String? phone;
|
||||||
|
@HiveField(10)
|
||||||
|
String? mobile;
|
||||||
@HiveField(11)
|
@HiveField(11)
|
||||||
final int fkEntite;
|
DateTime? dateNaissance;
|
||||||
|
@HiveField(12)
|
||||||
|
DateTime? dateEmbauche;
|
||||||
|
@HiveField(13)
|
||||||
|
final DateTime createdAt;
|
||||||
|
@HiveField(14)
|
||||||
|
bool isActive;
|
||||||
|
|
||||||
MembreModel({
|
MembreModel({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.fkRole,
|
this.fkEntite,
|
||||||
required this.fkTitre,
|
required this.role,
|
||||||
required this.firstName,
|
this.fkTitre,
|
||||||
|
this.name,
|
||||||
|
this.firstName,
|
||||||
|
this.username,
|
||||||
this.sectName,
|
this.sectName,
|
||||||
|
required this.email,
|
||||||
|
this.phone,
|
||||||
|
this.mobile,
|
||||||
this.dateNaissance,
|
this.dateNaissance,
|
||||||
this.dateEmbauche,
|
this.dateEmbauche,
|
||||||
required this.chkActive,
|
required this.createdAt,
|
||||||
required this.name,
|
required this.isActive,
|
||||||
required this.username,
|
|
||||||
required this.email,
|
|
||||||
required this.fkEntite,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Factory pour convertir depuis JSON (API)
|
// Factory pour convertir depuis JSON (API)
|
||||||
@@ -61,35 +63,53 @@ class MembreModel extends HiveObject {
|
|||||||
final dynamic rawId = json['id'];
|
final dynamic rawId = json['id'];
|
||||||
final int id = rawId is String ? int.parse(rawId) : rawId as int;
|
final int id = rawId is String ? int.parse(rawId) : rawId as int;
|
||||||
|
|
||||||
// Convertir le rôle en int, qu'il soit déjà int ou string
|
// Convertir le rôle en int (ATTENTION: le champ JSON est 'fk_role' pas 'role')
|
||||||
final dynamic rawRole = json['fk_role'];
|
final dynamic rawRole = json['fk_role']; // Correction ici !
|
||||||
final int fkRole = rawRole is String ? int.parse(rawRole) : rawRole as int;
|
final int role = rawRole is String ? int.parse(rawRole) : rawRole as int;
|
||||||
|
|
||||||
// Convertir le titre en int, qu'il soit déjà int ou string
|
// Convertir fkEntite en int si présent
|
||||||
final dynamic rawTitre = json['fk_titre'];
|
int? fkEntite;
|
||||||
final int fkTitre = rawTitre is String ? int.parse(rawTitre) : rawTitre as int;
|
if (json['fk_entite'] != null) {
|
||||||
|
|
||||||
// Convertir le chkActive en int, qu'il soit déjà int ou string
|
|
||||||
final dynamic rawActive = json['chk_active'];
|
|
||||||
final int chkActive = rawActive is String ? int.parse(rawActive) : rawActive as int;
|
|
||||||
|
|
||||||
// Convertir le fkEntite en int, qu'il soit déjà int ou string
|
|
||||||
final dynamic rawEntite = json['fk_entite'];
|
final dynamic rawEntite = json['fk_entite'];
|
||||||
final int fkEntite = rawEntite is String ? int.parse(rawEntite) : rawEntite as int;
|
fkEntite = rawEntite is String ? int.parse(rawEntite) : rawEntite as int;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convertir fkTitre en int si présent
|
||||||
|
int? fkTitre;
|
||||||
|
if (json['fk_titre'] != null) {
|
||||||
|
final dynamic rawTitre = json['fk_titre'];
|
||||||
|
fkTitre = rawTitre is String ? int.parse(rawTitre) : rawTitre as int;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gérer les dates nulles ou avec des valeurs invalides comme "0000-00-00"
|
||||||
|
DateTime? parseDate(String? dateStr) {
|
||||||
|
if (dateStr == null || dateStr.isEmpty || dateStr == "0000-00-00") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return DateTime.parse(dateStr);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return MembreModel(
|
return MembreModel(
|
||||||
id: id,
|
id: id,
|
||||||
fkRole: fkRole,
|
|
||||||
fkTitre: fkTitre,
|
|
||||||
firstName: json['first_name'] ?? '',
|
|
||||||
sectName: json['sect_name'],
|
|
||||||
dateNaissance: json['date_naissance'] != null ? DateTime.parse(json['date_naissance']) : null,
|
|
||||||
dateEmbauche: json['date_embauche'] != null ? DateTime.parse(json['date_embauche']) : null,
|
|
||||||
chkActive: chkActive,
|
|
||||||
name: json['name'] ?? '',
|
|
||||||
username: json['username'] ?? '',
|
|
||||||
email: json['email'] ?? '',
|
|
||||||
fkEntite: fkEntite,
|
fkEntite: fkEntite,
|
||||||
|
role: role,
|
||||||
|
fkTitre: fkTitre,
|
||||||
|
name: json['name'],
|
||||||
|
firstName: json['first_name'],
|
||||||
|
username: json['username'],
|
||||||
|
sectName: json['sect_name'],
|
||||||
|
email: json['email'] ?? '',
|
||||||
|
phone: json['phone'],
|
||||||
|
mobile: json['mobile'],
|
||||||
|
dateNaissance: parseDate(json['date_naissance']),
|
||||||
|
dateEmbauche: parseDate(json['date_embauche']),
|
||||||
|
createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : DateTime.now(),
|
||||||
|
// Le champ JSON est 'chk_active' pas 'is_active'
|
||||||
|
isActive: json['chk_active'] == 1 || json['chk_active'] == true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,47 +117,56 @@ class MembreModel extends HiveObject {
|
|||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'id': id,
|
'id': id,
|
||||||
'fk_role': fkRole,
|
'fk_entite': fkEntite,
|
||||||
|
'fk_role': role, // Changé pour correspondre à l'API
|
||||||
'fk_titre': fkTitre,
|
'fk_titre': fkTitre,
|
||||||
|
'name': name,
|
||||||
'first_name': firstName,
|
'first_name': firstName,
|
||||||
|
'username': username,
|
||||||
'sect_name': sectName,
|
'sect_name': sectName,
|
||||||
|
'email': email,
|
||||||
|
'phone': phone,
|
||||||
|
'mobile': mobile,
|
||||||
'date_naissance': dateNaissance?.toIso8601String(),
|
'date_naissance': dateNaissance?.toIso8601String(),
|
||||||
'date_embauche': dateEmbauche?.toIso8601String(),
|
'date_embauche': dateEmbauche?.toIso8601String(),
|
||||||
'chk_active': chkActive,
|
'created_at': createdAt.toIso8601String(),
|
||||||
'name': name,
|
'chk_active': isActive ? 1 : 0, // Changé pour correspondre à l'API
|
||||||
'username': username,
|
|
||||||
'email': email,
|
|
||||||
'fk_entite': fkEntite,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copier avec de nouvelles valeurs
|
// Copier avec de nouvelles valeurs
|
||||||
MembreModel copyWith({
|
MembreModel copyWith({
|
||||||
int? fkRole,
|
int? fkEntite,
|
||||||
|
int? role,
|
||||||
int? fkTitre,
|
int? fkTitre,
|
||||||
|
String? name,
|
||||||
String? firstName,
|
String? firstName,
|
||||||
|
String? username,
|
||||||
String? sectName,
|
String? sectName,
|
||||||
|
String? email,
|
||||||
|
String? phone,
|
||||||
|
String? mobile,
|
||||||
DateTime? dateNaissance,
|
DateTime? dateNaissance,
|
||||||
DateTime? dateEmbauche,
|
DateTime? dateEmbauche,
|
||||||
int? chkActive,
|
DateTime? createdAt,
|
||||||
String? name,
|
bool? isActive,
|
||||||
String? username,
|
|
||||||
String? email,
|
|
||||||
int? fkEntite,
|
|
||||||
}) {
|
}) {
|
||||||
return MembreModel(
|
return MembreModel(
|
||||||
id: id,
|
id: id,
|
||||||
fkRole: fkRole ?? this.fkRole,
|
fkEntite: fkEntite ?? this.fkEntite,
|
||||||
|
role: role ?? this.role,
|
||||||
fkTitre: fkTitre ?? this.fkTitre,
|
fkTitre: fkTitre ?? this.fkTitre,
|
||||||
|
name: name ?? this.name,
|
||||||
firstName: firstName ?? this.firstName,
|
firstName: firstName ?? this.firstName,
|
||||||
|
username: username ?? this.username,
|
||||||
sectName: sectName ?? this.sectName,
|
sectName: sectName ?? this.sectName,
|
||||||
|
email: email ?? this.email,
|
||||||
|
phone: phone ?? this.phone,
|
||||||
|
mobile: mobile ?? this.mobile,
|
||||||
dateNaissance: dateNaissance ?? this.dateNaissance,
|
dateNaissance: dateNaissance ?? this.dateNaissance,
|
||||||
dateEmbauche: dateEmbauche ?? this.dateEmbauche,
|
dateEmbauche: dateEmbauche ?? this.dateEmbauche,
|
||||||
chkActive: chkActive ?? this.chkActive,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
name: name ?? this.name,
|
isActive: isActive ?? this.isActive,
|
||||||
username: username ?? this.username,
|
|
||||||
email: email ?? this.email,
|
|
||||||
fkEntite: fkEntite ?? this.fkEntite,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,48 +18,57 @@ class MembreModelAdapter extends TypeAdapter<MembreModel> {
|
|||||||
};
|
};
|
||||||
return MembreModel(
|
return MembreModel(
|
||||||
id: fields[0] as int,
|
id: fields[0] as int,
|
||||||
fkRole: fields[1] as int,
|
fkEntite: fields[1] as int?,
|
||||||
fkTitre: fields[2] as int,
|
role: fields[2] as int,
|
||||||
firstName: fields[3] as String,
|
fkTitre: fields[3] as int?,
|
||||||
sectName: fields[4] as String?,
|
name: fields[4] as String?,
|
||||||
dateNaissance: fields[5] as DateTime?,
|
firstName: fields[5] as String?,
|
||||||
dateEmbauche: fields[6] as DateTime?,
|
username: fields[6] as String?,
|
||||||
chkActive: fields[7] as int,
|
sectName: fields[7] as String?,
|
||||||
name: fields[8] as String,
|
email: fields[8] as String,
|
||||||
username: fields[9] as String,
|
phone: fields[9] as String?,
|
||||||
email: fields[10] as String,
|
mobile: fields[10] as String?,
|
||||||
fkEntite: fields[11] as int,
|
dateNaissance: fields[11] as DateTime?,
|
||||||
|
dateEmbauche: fields[12] as DateTime?,
|
||||||
|
createdAt: fields[13] as DateTime,
|
||||||
|
isActive: fields[14] as bool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void write(BinaryWriter writer, MembreModel obj) {
|
void write(BinaryWriter writer, MembreModel obj) {
|
||||||
writer
|
writer
|
||||||
..writeByte(12)
|
..writeByte(15)
|
||||||
..writeByte(0)
|
..writeByte(0)
|
||||||
..write(obj.id)
|
..write(obj.id)
|
||||||
..writeByte(1)
|
..writeByte(1)
|
||||||
..write(obj.fkRole)
|
..write(obj.fkEntite)
|
||||||
..writeByte(2)
|
..writeByte(2)
|
||||||
..write(obj.fkTitre)
|
..write(obj.role)
|
||||||
..writeByte(3)
|
..writeByte(3)
|
||||||
..write(obj.firstName)
|
..write(obj.fkTitre)
|
||||||
..writeByte(4)
|
..writeByte(4)
|
||||||
..write(obj.sectName)
|
|
||||||
..writeByte(5)
|
|
||||||
..write(obj.dateNaissance)
|
|
||||||
..writeByte(6)
|
|
||||||
..write(obj.dateEmbauche)
|
|
||||||
..writeByte(7)
|
|
||||||
..write(obj.chkActive)
|
|
||||||
..writeByte(8)
|
|
||||||
..write(obj.name)
|
..write(obj.name)
|
||||||
..writeByte(9)
|
..writeByte(5)
|
||||||
|
..write(obj.firstName)
|
||||||
|
..writeByte(6)
|
||||||
..write(obj.username)
|
..write(obj.username)
|
||||||
..writeByte(10)
|
..writeByte(7)
|
||||||
|
..write(obj.sectName)
|
||||||
|
..writeByte(8)
|
||||||
..write(obj.email)
|
..write(obj.email)
|
||||||
|
..writeByte(9)
|
||||||
|
..write(obj.phone)
|
||||||
|
..writeByte(10)
|
||||||
|
..write(obj.mobile)
|
||||||
..writeByte(11)
|
..writeByte(11)
|
||||||
..write(obj.fkEntite);
|
..write(obj.dateNaissance)
|
||||||
|
..writeByte(12)
|
||||||
|
..write(obj.dateEmbauche)
|
||||||
|
..writeByte(13)
|
||||||
|
..write(obj.createdAt)
|
||||||
|
..writeByte(14)
|
||||||
|
..write(obj.isActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'package:hive/hive.dart';
|
|||||||
|
|
||||||
part 'region_model.g.dart';
|
part 'region_model.g.dart';
|
||||||
|
|
||||||
@HiveType(typeId: 7) // Assurez-vous que cet ID est unique
|
@HiveType(typeId: 7)
|
||||||
class RegionModel extends HiveObject {
|
class RegionModel extends HiveObject {
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
final int id;
|
final int id;
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ part 'user_sector_model.g.dart';
|
|||||||
///
|
///
|
||||||
/// Cette classe représente l'association entre un utilisateur et un secteur,
|
/// Cette classe représente l'association entre un utilisateur et un secteur,
|
||||||
/// telle que reçue de l'API dans la réponse users_sectors.
|
/// telle que reçue de l'API dans la réponse users_sectors.
|
||||||
@HiveType(
|
@HiveType(typeId: 6)
|
||||||
typeId: 7) // Assurez-vous que cet ID est unique parmi vos modèles Hive
|
|
||||||
class UserSectorModel extends HiveObject {
|
class UserSectorModel extends HiveObject {
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
final int id; // ID de l'utilisateur
|
final int id; // ID de l'utilisateur
|
||||||
@@ -38,9 +37,7 @@ class UserSectorModel extends HiveObject {
|
|||||||
id: json['id'] is String ? int.parse(json['id']) : json['id'],
|
id: json['id'] is String ? int.parse(json['id']) : json['id'],
|
||||||
firstName: json['first_name'],
|
firstName: json['first_name'],
|
||||||
sectName: json['sect_name'],
|
sectName: json['sect_name'],
|
||||||
fkSector: json['fk_sector'] is String
|
fkSector: json['fk_sector'] is String ? int.parse(json['fk_sector']) : json['fk_sector'],
|
||||||
? int.parse(json['fk_sector'])
|
|
||||||
: json['fk_sector'],
|
|
||||||
name: json['name'],
|
name: json['name'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ part of 'user_sector_model.dart';
|
|||||||
|
|
||||||
class UserSectorModelAdapter extends TypeAdapter<UserSectorModel> {
|
class UserSectorModelAdapter extends TypeAdapter<UserSectorModel> {
|
||||||
@override
|
@override
|
||||||
final int typeId = 7;
|
final int typeId = 6;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
UserSectorModel read(BinaryReader reader) {
|
UserSectorModel read(BinaryReader reader) {
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
|
||||||
import 'dart:async';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||||
import 'package:geosector_app/core/services/api_service.dart';
|
import 'package:geosector_app/core/services/api_service.dart';
|
||||||
@@ -34,6 +31,19 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Méthode pour exposer la Box Hive (nécessaire pour ValueListenableBuilder)
|
||||||
|
Box<AmicaleModel> getAmicalesBox() {
|
||||||
|
try {
|
||||||
|
if (!Hive.isBoxOpen(AppKeys.amicaleBoxName)) {
|
||||||
|
throw Exception('La boîte amicales n\'est pas ouverte');
|
||||||
|
}
|
||||||
|
return _amicaleBox;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Erreur lors de l\'accès à la boîte amicales: $e');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Récupérer toutes les amicales
|
// Récupérer toutes les amicales
|
||||||
List<AmicaleModel> getAllAmicales() {
|
List<AmicaleModel> getAllAmicales() {
|
||||||
return _amicaleBox.values.toList();
|
return _amicaleBox.values.toList();
|
||||||
@@ -54,6 +64,16 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
return getAmicalesByType(1);
|
return getAmicalesByType(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Récupérer l'amicale de l'utilisateur connecté (basé sur fkEntite)
|
||||||
|
AmicaleModel? getAmicaleByUserId(int userId, int fkEntite) {
|
||||||
|
try {
|
||||||
|
return _amicaleBox.get(fkEntite);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Erreur lors de la récupération de l\'amicale de l\'utilisateur: $e');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sauvegarder une amicale
|
// Sauvegarder une amicale
|
||||||
Future<void> saveAmicale(AmicaleModel amicale) async {
|
Future<void> saveAmicale(AmicaleModel amicale) async {
|
||||||
await _amicaleBox.put(amicale.id, amicale);
|
await _amicaleBox.put(amicale.id, amicale);
|
||||||
@@ -66,6 +86,12 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vider la boîte des amicales
|
||||||
|
Future<void> clearAmicales() async {
|
||||||
|
await _amicaleBox.clear();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
// Créer une amicale via l'API
|
// Créer une amicale via l'API
|
||||||
Future<bool> createAmicale(AmicaleModel amicale) async {
|
Future<bool> createAmicale(AmicaleModel amicale) async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
@@ -82,14 +108,33 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
// Récupérer l'ID de la nouvelle amicale
|
// Récupérer l'ID de la nouvelle amicale
|
||||||
final amicaleId = response.data['id'] is String ? int.parse(response.data['id']) : response.data['id'] as int;
|
final amicaleId = response.data['id'] is String ? int.parse(response.data['id']) : response.data['id'] as int;
|
||||||
|
|
||||||
// Créer l'amicale localement avec l'ID retourné par l'API
|
// Créer l'amicale localement avec l'ID retourné par l'API et updatedAt
|
||||||
final newAmicale = amicale.copyWith(
|
final amicaleWithNewId = AmicaleModel(
|
||||||
id: amicaleId,
|
id: amicaleId,
|
||||||
lastSyncedAt: DateTime.now(),
|
name: amicale.name,
|
||||||
isSynced: true,
|
adresse1: amicale.adresse1,
|
||||||
|
adresse2: amicale.adresse2,
|
||||||
|
codePostal: amicale.codePostal,
|
||||||
|
ville: amicale.ville,
|
||||||
|
fkRegion: amicale.fkRegion,
|
||||||
|
libRegion: amicale.libRegion,
|
||||||
|
fkType: amicale.fkType,
|
||||||
|
phone: amicale.phone,
|
||||||
|
mobile: amicale.mobile,
|
||||||
|
email: amicale.email,
|
||||||
|
gpsLat: amicale.gpsLat,
|
||||||
|
gpsLng: amicale.gpsLng,
|
||||||
|
stripeId: amicale.stripeId,
|
||||||
|
chkDemo: amicale.chkDemo,
|
||||||
|
chkCopieMailRecu: amicale.chkCopieMailRecu,
|
||||||
|
chkAcceptSms: amicale.chkAcceptSms,
|
||||||
|
chkActive: amicale.chkActive,
|
||||||
|
chkStripe: amicale.chkStripe,
|
||||||
|
createdAt: amicale.createdAt ?? DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
);
|
);
|
||||||
|
|
||||||
await saveAmicale(newAmicale);
|
await saveAmicale(amicaleWithNewId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,10 +161,9 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
final response = await ApiService.instance.put('/amicales/${amicale.id}', data: data);
|
final response = await ApiService.instance.put('/amicales/${amicale.id}', data: data);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// Mettre à jour l'amicale localement
|
// Mettre à jour l'amicale localement avec updatedAt
|
||||||
final updatedAmicale = amicale.copyWith(
|
final updatedAmicale = amicale.copyWith(
|
||||||
lastSyncedAt: DateTime.now(),
|
updatedAt: DateTime.now(),
|
||||||
isSynced: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await saveAmicale(updatedAmicale);
|
await saveAmicale(updatedAmicale);
|
||||||
@@ -136,6 +180,35 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mettre à jour une amicale via l'API (version alternative avec retour d'objet)
|
||||||
|
Future<AmicaleModel?> updateAmicaleViaApi(AmicaleModel amicale) async {
|
||||||
|
_isLoading = true;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await ApiService.instance.put(
|
||||||
|
'/amicales/${amicale.id}',
|
||||||
|
data: amicale.toJson(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final updatedAmicaleData = response.data;
|
||||||
|
final updatedAmicale = AmicaleModel.fromJson(updatedAmicaleData);
|
||||||
|
await saveAmicale(updatedAmicale);
|
||||||
|
return updatedAmicale;
|
||||||
|
} else {
|
||||||
|
debugPrint('Erreur lors de la mise à jour de l\'amicale: ${response.statusCode}');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Erreur lors de la mise à jour de l\'amicale: $e');
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
_isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Supprimer une amicale via l'API
|
// Supprimer une amicale via l'API
|
||||||
Future<bool> deleteAmicaleViaApi(int id) async {
|
Future<bool> deleteAmicaleViaApi(int id) async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
@@ -161,218 +234,45 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traitement des données d'amicales depuis l'API
|
// Traitement des données d'amicale depuis l'API (amicale unique)
|
||||||
Future<void> processAmicalesData(dynamic amicalesData) async {
|
Future<void> processAmicalesData(dynamic amicaleData) async {
|
||||||
try {
|
try {
|
||||||
debugPrint('Traitement des données des amicales...');
|
debugPrint('Traitement de l\'amicale utilisateur...');
|
||||||
|
|
||||||
// Vérifier que les données sont au bon format
|
// Vérifier que les données sont au bon format
|
||||||
if (amicalesData == null) {
|
if (amicaleData == null) {
|
||||||
debugPrint('Aucune donnée d\'amicale à traiter');
|
debugPrint('Aucune donnée d\'amicale à traiter');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<dynamic> amicalesList;
|
// Vider la boîte avant d'ajouter la nouvelle amicale
|
||||||
if (amicalesData is List) {
|
|
||||||
amicalesList = amicalesData;
|
|
||||||
} else if (amicalesData is Map && amicalesData.containsKey('data')) {
|
|
||||||
amicalesList = amicalesData['data'] as List<dynamic>;
|
|
||||||
} else {
|
|
||||||
debugPrint('Format de données d\'amicales non reconnu');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vider la boîte avant d'ajouter les nouvelles données
|
|
||||||
await _amicaleBox.clear();
|
await _amicaleBox.clear();
|
||||||
|
|
||||||
// Traiter chaque amicale
|
|
||||||
int count = 0;
|
|
||||||
for (final amicaleData in amicalesList) {
|
|
||||||
try {
|
try {
|
||||||
final amicale = AmicaleModel.fromJson(amicaleData);
|
// Les données sont un objet amicale unique
|
||||||
await _amicaleBox.put(amicale.id, amicale);
|
final Map<String, dynamic> amicaleMap = Map<String, dynamic>.from(amicaleData as Map);
|
||||||
count++;
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors du traitement d\'une amicale: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint('$count amicales traitées et stockées');
|
|
||||||
notifyListeners();
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors du traitement des amicales: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
import 'package:geosector_app/core/services/api_service.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
|
||||||
|
|
||||||
class AmicaleRepository extends ChangeNotifier {
|
|
||||||
// Utilisation de getters lazy pour n'accéder à la boîte que lorsque nécessaire
|
|
||||||
Box<AmicaleModel> get _amicaleBox => Hive.box<AmicaleModel>(AppKeys.amicaleBoxName);
|
|
||||||
|
|
||||||
final ApiService _apiService;
|
|
||||||
bool _isLoading = false;
|
|
||||||
|
|
||||||
AmicaleRepository(this._apiService);
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
bool get isLoading => _isLoading;
|
|
||||||
|
|
||||||
// Méthode pour exposer la Box Hive (nécessaire pour ValueListenableBuilder)
|
|
||||||
Box<AmicaleModel> getAmicalesBox() {
|
|
||||||
try {
|
|
||||||
if (!Hive.isBoxOpen(AppKeys.amicaleBoxName)) {
|
|
||||||
throw Exception('La boîte amicales n\'est pas ouverte');
|
|
||||||
}
|
|
||||||
return _amicaleBox;
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors de l\'accès à la boîte amicales: $e');
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Méthode pour vérifier si une boîte est ouverte et l'ouvrir si nécessaire
|
|
||||||
Future<void> _ensureBoxIsOpen() async {
|
|
||||||
try {
|
|
||||||
if (!Hive.isBoxOpen(AppKeys.amicaleBoxName)) {
|
|
||||||
debugPrint('Ouverture de la boîte amicale...');
|
|
||||||
await Hive.openBox<AmicaleModel>(AppKeys.amicaleBoxName);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors de l\'ouverture de la boîte amicale: $e');
|
|
||||||
throw Exception('Impossible d\'ouvrir la boîte amicale: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Récupérer toutes les amicales
|
|
||||||
List<AmicaleModel> getAllAmicales() {
|
|
||||||
try {
|
|
||||||
_ensureBoxIsOpen();
|
|
||||||
return _amicaleBox.values.toList();
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors de la récupération des amicales: $e');
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Récupérer une amicale par son ID
|
|
||||||
AmicaleModel? getAmicaleById(int id) {
|
|
||||||
try {
|
|
||||||
_ensureBoxIsOpen();
|
|
||||||
return _amicaleBox.get(id);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors de la récupération de l\'amicale: $e');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Récupérer l'amicale de l'utilisateur connecté (basé sur fkEntite)
|
|
||||||
AmicaleModel? getAmicaleByUserId(int userId, int fkEntite) {
|
|
||||||
try {
|
|
||||||
_ensureBoxIsOpen();
|
|
||||||
return _amicaleBox.get(fkEntite);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors de la récupération de l\'amicale de l\'utilisateur: $e');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Créer ou mettre à jour une amicale localement
|
|
||||||
Future<AmicaleModel> saveAmicale(AmicaleModel amicale) async {
|
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _amicaleBox.put(amicale.id, amicale);
|
|
||||||
notifyListeners(); // Notifier les changements pour mettre à jour l'UI
|
|
||||||
return amicale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supprimer une amicale localement
|
|
||||||
Future<void> deleteAmicale(int id) async {
|
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _amicaleBox.delete(id);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vider la boîte des amicales
|
|
||||||
Future<void> clearAmicales() async {
|
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _amicaleBox.clear();
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traiter les données des amicales reçues de l'API
|
|
||||||
Future<void> processAmicalesData(dynamic amicalesData) async {
|
|
||||||
try {
|
|
||||||
debugPrint('Traitement des données des amicales...');
|
|
||||||
debugPrint('Détails amicale: $amicalesData');
|
|
||||||
|
|
||||||
// Vérifier que les données sont au bon format
|
|
||||||
if (amicalesData == null) {
|
|
||||||
debugPrint('Aucune donnée d\'amicale à traiter');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vider la boîte avant d'ajouter les nouvelles données
|
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _amicaleBox.clear();
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
// Cas 1: Les données sont une liste d'amicales
|
|
||||||
if (amicalesData is List) {
|
|
||||||
for (final amicaleData in amicalesData) {
|
|
||||||
try {
|
|
||||||
final amicale = AmicaleModel.fromJson(amicaleData);
|
|
||||||
await _amicaleBox.put(amicale.id, amicale);
|
|
||||||
count++;
|
|
||||||
debugPrint('Amicale traitée: ${amicale.name} (ID: ${amicale.id})');
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors du traitement d\'une amicale: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Cas 2: Les données sont un objet avec une clé 'data' contenant une liste
|
|
||||||
else if (amicalesData is Map && amicalesData.containsKey('data')) {
|
|
||||||
final amicalesList = amicalesData['data'] as List<dynamic>;
|
|
||||||
for (final amicaleData in amicalesList) {
|
|
||||||
try {
|
|
||||||
final amicale = AmicaleModel.fromJson(amicaleData);
|
|
||||||
await _amicaleBox.put(amicale.id, amicale);
|
|
||||||
count++;
|
|
||||||
debugPrint('Amicale traitée: ${amicale.name} (ID: ${amicale.id})');
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors du traitement d\'une amicale: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Cas 3: Les données sont un objet amicale unique (pas une liste)
|
|
||||||
else if (amicalesData is Map) {
|
|
||||||
try {
|
|
||||||
// Convertir Map<dynamic, dynamic> en Map<String, dynamic>
|
|
||||||
final Map<String, dynamic> amicaleMap = {};
|
|
||||||
amicalesData.forEach((key, value) {
|
|
||||||
if (key is String) {
|
|
||||||
amicaleMap[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final amicale = AmicaleModel.fromJson(amicaleMap);
|
final amicale = AmicaleModel.fromJson(amicaleMap);
|
||||||
await _amicaleBox.put(amicale.id, amicale);
|
await _amicaleBox.put(amicale.id, amicale);
|
||||||
count++;
|
debugPrint('✅ Amicale utilisateur traitée: ${amicale.name} (ID: ${amicale.id})');
|
||||||
debugPrint('Amicale unique traitée: ${amicale.name} (ID: ${amicale.id})');
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors du traitement de l\'amicale unique: $e');
|
|
||||||
debugPrint('Exception détaillée: $e');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
debugPrint('Format de données d\'amicale non reconnu');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint('$count amicales traitées et stockées');
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors du traitement des amicales: $e');
|
debugPrint('❌ Erreur lors du traitement de l\'amicale: $e');
|
||||||
|
debugPrint('Données reçues: $amicaleData');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur lors du traitement de l\'amicale: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode spécifique pour récupérer l'amicale de l'utilisateur connecté
|
||||||
|
AmicaleModel? getUserAmicale(int fkEntite) {
|
||||||
|
try {
|
||||||
|
final amicale = _amicaleBox.get(fkEntite);
|
||||||
|
debugPrint('🔍 Recherche amicale ID $fkEntite: ${amicale?.name ?? 'non trouvée'}');
|
||||||
|
return amicale;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur lors de la récupération de l\'amicale utilisateur: $e');
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,7 +282,7 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await _apiService.get('/amicales');
|
final response = await ApiService.instance.get('/amicales');
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final amicalesData = response.data;
|
final amicalesData = response.data;
|
||||||
@@ -407,7 +307,7 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await _apiService.get('/amicales/$id');
|
final response = await ApiService.instance.get('/amicales/$id');
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final amicaleData = response.data;
|
final amicaleData = response.data;
|
||||||
@@ -427,34 +327,7 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mettre à jour une amicale via l'API
|
// === MÉTHODES DE FILTRAGE ET RECHERCHE ===
|
||||||
Future<AmicaleModel?> updateAmicaleViaApi(AmicaleModel amicale) async {
|
|
||||||
_isLoading = true;
|
|
||||||
notifyListeners();
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await _apiService.put(
|
|
||||||
'/amicales/${amicale.id}',
|
|
||||||
data: amicale.toJson(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
final updatedAmicaleData = response.data;
|
|
||||||
final updatedAmicale = AmicaleModel.fromJson(updatedAmicaleData);
|
|
||||||
await saveAmicale(updatedAmicale);
|
|
||||||
return updatedAmicale;
|
|
||||||
} else {
|
|
||||||
debugPrint('Erreur lors de la mise à jour de l\'amicale: ${response.statusCode}');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors de la mise à jour de l\'amicale: $e');
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
_isLoading = false;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filtrer les amicales par nom
|
// Filtrer les amicales par nom
|
||||||
List<AmicaleModel> searchAmicalesByName(String query) {
|
List<AmicaleModel> searchAmicalesByName(String query) {
|
||||||
@@ -466,11 +339,6 @@ class AmicaleRepository extends ChangeNotifier {
|
|||||||
return _amicaleBox.values.where((amicale) => amicale.name.toLowerCase().contains(lowercaseQuery)).toList();
|
return _amicaleBox.values.where((amicale) => amicale.name.toLowerCase().contains(lowercaseQuery)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filtrer les amicales par type
|
|
||||||
List<AmicaleModel> getAmicalesByType(int type) {
|
|
||||||
return _amicaleBox.values.where((amicale) => amicale.fkType == type).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filtrer les amicales par région
|
// Filtrer les amicales par région
|
||||||
List<AmicaleModel> getAmicalesByRegion(int regionId) {
|
List<AmicaleModel> getAmicalesByRegion(int regionId) {
|
||||||
return _amicaleBox.values.where((amicale) => amicale.fkRegion == regionId).toList();
|
return _amicaleBox.values.where((amicale) => amicale.fkRegion == regionId).toList();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:geosector_app/core/constants/app_keys.dart';
|
|||||||
class ClientRepository extends ChangeNotifier {
|
class ClientRepository extends ChangeNotifier {
|
||||||
// Constructeur sans paramètres - utilise ApiService.instance
|
// Constructeur sans paramètres - utilise ApiService.instance
|
||||||
ClientRepository();
|
ClientRepository();
|
||||||
|
|
||||||
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
|
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
|
||||||
// et vérifier qu'elle est ouverte avant accès
|
// et vérifier qu'elle est ouverte avant accès
|
||||||
Box<ClientModel> get _clientBox {
|
Box<ClientModel> get _clientBox {
|
||||||
@@ -58,8 +59,11 @@ class ClientRepository extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Préparer les données pour l'API
|
// Préparer les données pour l'API - exclure l'id pour la création
|
||||||
final data = client.toJson();
|
final data = client.toJson();
|
||||||
|
data.remove('id'); // L'API génère l'ID
|
||||||
|
data.remove('created_at'); // L'API génère created_at
|
||||||
|
data.remove('updated_at'); // L'API génère updated_at
|
||||||
|
|
||||||
// Appeler l'API pour créer le client
|
// Appeler l'API pour créer le client
|
||||||
final response = await ApiService.instance.post('/clients', data: data);
|
final response = await ApiService.instance.post('/clients', data: data);
|
||||||
@@ -70,11 +74,13 @@ class ClientRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
// Créer le client localement avec l'ID retourné par l'API
|
// Créer le client localement avec l'ID retourné par l'API
|
||||||
final newClient = client.copyWith(
|
final newClient = client.copyWith(
|
||||||
id: clientId,
|
createdAt: DateTime.now(),
|
||||||
lastSyncedAt: DateTime.now(),
|
updatedAt: DateTime.now(),
|
||||||
isSynced: true,
|
|
||||||
);
|
);
|
||||||
await saveClient(newClient);
|
|
||||||
|
// Sauvegarder avec le nouvel ID
|
||||||
|
await _clientBox.put(clientId, newClient);
|
||||||
|
notifyListeners();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -95,17 +101,14 @@ class ClientRepository extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
// Préparer les données pour l'API
|
// Préparer les données pour l'API
|
||||||
final data = client.toJson();
|
final data = client.toJson();
|
||||||
|
|
||||||
// Appeler l'API pour mettre à jour le client
|
// Appeler l'API pour mettre à jour le client
|
||||||
final response = await ApiService.instance.put('/clients/${client.id}', data: data);
|
final response = await ApiService.instance.put('/clients/${client.id}', data: data);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// Mettre à jour le client localement
|
// Mettre à jour le client localement avec updatedAt
|
||||||
final updatedClient = client.copyWith(
|
final updatedClient = client.copyWith(
|
||||||
lastSyncedAt: DateTime.now(),
|
updatedAt: DateTime.now(),
|
||||||
isSynced: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await saveClient(updatedClient);
|
await saveClient(updatedClient);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -190,7 +193,6 @@ class ClientRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
// Vider la boîte des clients
|
// Vider la boîte des clients
|
||||||
Future<void> clearClients() async {
|
Future<void> clearClients() async {
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _clientBox.clear();
|
await _clientBox.clear();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@@ -220,6 +222,7 @@ class ClientRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === MÉTHODES DE FILTRAGE ET RECHERCHE ===
|
||||||
// Filtrer les clients par nom
|
// Filtrer les clients par nom
|
||||||
List<ClientModel> searchClientsByName(String query) {
|
List<ClientModel> searchClientsByName(String query) {
|
||||||
if (query.isEmpty) {
|
if (query.isEmpty) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:geosector_app/core/constants/app_keys.dart';
|
|||||||
class MembreRepository extends ChangeNotifier {
|
class MembreRepository extends ChangeNotifier {
|
||||||
// Constructeur sans paramètres - utilise ApiService.instance
|
// Constructeur sans paramètres - utilise ApiService.instance
|
||||||
MembreRepository();
|
MembreRepository();
|
||||||
|
|
||||||
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
|
// Utiliser un getter lazy pour n'accéder à la boîte que lorsque nécessaire
|
||||||
// et vérifier qu'elle est ouverte avant accès
|
// et vérifier qu'elle est ouverte avant accès
|
||||||
Box<MembreModel> get _membreBox {
|
Box<MembreModel> get _membreBox {
|
||||||
@@ -43,6 +44,9 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === MÉTHODES SPÉCIFIQUES AUX MEMBRES ===
|
||||||
|
|
||||||
|
// Récupérer les membres par amicale
|
||||||
List<MembreModel> getMembresByAmicale(int fkEntite) {
|
List<MembreModel> getMembresByAmicale(int fkEntite) {
|
||||||
try {
|
try {
|
||||||
return _membreBox.values.where((membre) => membre.fkEntite == fkEntite).toList();
|
return _membreBox.values.where((membre) => membre.fkEntite == fkEntite).toList();
|
||||||
@@ -55,7 +59,7 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
// Récupérer les membres actifs par amicale
|
// Récupérer les membres actifs par amicale
|
||||||
List<MembreModel> getActiveMembresByAmicale(int fkEntite) {
|
List<MembreModel> getActiveMembresByAmicale(int fkEntite) {
|
||||||
try {
|
try {
|
||||||
return _membreBox.values.where((membre) => membre.fkEntite == fkEntite && membre.chkActive == 1).toList();
|
return _membreBox.values.where((membre) => membre.fkEntite == fkEntite && membre.isActive == true).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de la récupération des membres actifs par amicale: $e');
|
debugPrint('Erreur lors de la récupération des membres actifs par amicale: $e');
|
||||||
return [];
|
return [];
|
||||||
@@ -72,6 +76,8 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === MÉTHODES CRUD DE BASE ===
|
||||||
|
|
||||||
// Récupérer tous les membres
|
// Récupérer tous les membres
|
||||||
List<MembreModel> getAllMembres() {
|
List<MembreModel> getAllMembres() {
|
||||||
try {
|
try {
|
||||||
@@ -94,27 +100,28 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
|
|
||||||
// Sauvegarder un membre
|
// Sauvegarder un membre
|
||||||
Future<void> saveMembre(MembreModel membre) async {
|
Future<void> saveMembre(MembreModel membre) async {
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _membreBox.put(membre.id, membre);
|
await _membreBox.put(membre.id, membre);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supprimer un membre
|
// Supprimer un membre
|
||||||
Future<void> deleteMembre(int id) async {
|
Future<void> deleteMembre(int id) async {
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _membreBox.delete(id);
|
await _membreBox.delete(id);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === MÉTHODES API ===
|
||||||
|
|
||||||
// Créer un membre via l'API
|
// Créer un membre via l'API
|
||||||
Future<bool> createMembre(MembreModel membre) async {
|
Future<bool> createMembre(MembreModel membre) async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Préparer les données pour l'API
|
// Préparer les données pour l'API - exclure l'id pour la création
|
||||||
final data = membre.toJson();
|
final data = membre.toJson();
|
||||||
|
data.remove('id'); // L'API génère l'ID
|
||||||
|
data.remove('created_at'); // L'API génère created_at
|
||||||
// Appeler l'API pour créer le membre
|
// Appeler l'API pour créer le membre
|
||||||
final response = await ApiService.instance.post('/membres', data: data);
|
final response = await ApiService.instance.post('/membres', data: data);
|
||||||
|
|
||||||
@@ -123,11 +130,24 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
final membreId = response.data['id'] is String ? int.parse(response.data['id']) : response.data['id'] as int;
|
final membreId = response.data['id'] is String ? int.parse(response.data['id']) : response.data['id'] as int;
|
||||||
|
|
||||||
// Créer le membre localement avec l'ID retourné par l'API
|
// Créer le membre localement avec l'ID retourné par l'API
|
||||||
final newMembre = membre.copyWith(
|
final newMembre = MembreModel(
|
||||||
id: membreId,
|
id: membreId,
|
||||||
lastSyncedAt: DateTime.now(),
|
fkEntite: membre.fkEntite,
|
||||||
isSynced: true,
|
role: membre.role,
|
||||||
|
fkTitre: membre.fkTitre,
|
||||||
|
name: membre.name,
|
||||||
|
firstName: membre.firstName,
|
||||||
|
username: membre.username,
|
||||||
|
sectName: membre.sectName,
|
||||||
|
email: membre.email,
|
||||||
|
phone: membre.phone,
|
||||||
|
mobile: membre.mobile,
|
||||||
|
dateNaissance: membre.dateNaissance,
|
||||||
|
dateEmbauche: membre.dateEmbauche,
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
isActive: membre.isActive,
|
||||||
);
|
);
|
||||||
|
|
||||||
await saveMembre(newMembre);
|
await saveMembre(newMembre);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -154,13 +174,8 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
final response = await ApiService.instance.put('/membres/${membre.id}', data: data);
|
final response = await ApiService.instance.put('/membres/${membre.id}', data: data);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
// Mettre à jour le membre localement
|
// Sauvegarder le membre mis à jour localement
|
||||||
final updatedMembre = membre.copyWith(
|
await saveMembre(membre);
|
||||||
lastSyncedAt: DateTime.now(),
|
|
||||||
isSynced: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
await saveMembre(updatedMembre);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +214,8 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === TRAITEMENT DES DONNÉES ===
|
||||||
|
|
||||||
// Traitement des données de membres depuis l'API
|
// Traitement des données de membres depuis l'API
|
||||||
Future<void> processMembresData(dynamic membresData) async {
|
Future<void> processMembresData(dynamic membresData) async {
|
||||||
try {
|
try {
|
||||||
@@ -221,9 +238,7 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vider la boîte avant d'ajouter les nouvelles données
|
// Vider la boîte avant d'ajouter les nouvelles données
|
||||||
await _ensureBoxIsOpen();
|
|
||||||
await _membreBox.clear();
|
await _membreBox.clear();
|
||||||
|
|
||||||
// Traiter chaque membre
|
// Traiter chaque membre
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (final membreData in membresList) {
|
for (final membreData in membresList) {
|
||||||
@@ -242,4 +257,55 @@ class MembreRepository extends ChangeNotifier {
|
|||||||
debugPrint('Erreur lors du traitement des membres: $e');
|
debugPrint('Erreur lors du traitement des membres: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Récupérer les membres depuis l'API
|
||||||
|
Future<List<MembreModel>> fetchMembresFromApi() async {
|
||||||
|
_isLoading = true;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await ApiService.instance.get('/membres');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final membresData = response.data;
|
||||||
|
await processMembresData(membresData);
|
||||||
|
return getAllMembres();
|
||||||
|
} else {
|
||||||
|
debugPrint('Erreur lors de la récupération des membres: ${response.statusCode}');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Erreur lors de la récupération des membres: $e');
|
||||||
|
return [];
|
||||||
|
} finally {
|
||||||
|
_isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === MÉTHODES DE FILTRAGE ET RECHERCHE ===
|
||||||
|
|
||||||
|
// Filtrer les membres par nom
|
||||||
|
List<MembreModel> searchMembresByName(String query) {
|
||||||
|
if (query.isEmpty) {
|
||||||
|
return getAllMembres();
|
||||||
|
}
|
||||||
|
|
||||||
|
final lowercaseQuery = query.toLowerCase();
|
||||||
|
return _membreBox.values
|
||||||
|
.where(
|
||||||
|
(membre) => (membre.name?.toLowerCase().contains(lowercaseQuery) ?? false) || (membre.firstName?.toLowerCase().contains(lowercaseQuery) ?? false))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filtrer les membres actifs
|
||||||
|
List<MembreModel> getActiveMembres() {
|
||||||
|
return _membreBox.values.where((membre) => membre.isActive == true).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vider la boîte des membres
|
||||||
|
Future<void> clearMembres() async {
|
||||||
|
await _membreBox.clear();
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ class PassageRepository extends ChangeNotifier {
|
|||||||
return _passageBox.values.where((passage) => passage.fkType == type).toList();
|
return _passageBox.values.where((passage) => passage.fkType == type).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Récupérer les passages par opération
|
||||||
|
List<PassageModel> getPassagesByOperation(int operationId) {
|
||||||
|
return _passageBox.values.where((passage) => passage.fkOperation == operationId).toList();
|
||||||
|
}
|
||||||
|
|
||||||
// Récupérer les passages par date
|
// Récupérer les passages par date
|
||||||
List<PassageModel> getPassagesByDate(DateTime date) {
|
List<PassageModel> getPassagesByDate(DateTime date) {
|
||||||
return _passageBox.values.where((passage) {
|
return _passageBox.values.where((passage) {
|
||||||
|
|||||||
@@ -226,9 +226,6 @@ class UserRepository extends ChangeNotifier {
|
|||||||
try {
|
try {
|
||||||
debugPrint('🔐 Tentative de connexion: $username');
|
debugPrint('🔐 Tentative de connexion: $username');
|
||||||
|
|
||||||
// Étape 1: Nettoyage des données via DataLoadingService
|
|
||||||
await DataLoadingService.instance.cleanDataBeforeLogin();
|
|
||||||
|
|
||||||
// Étape 2: Connexion à l'API (25%)
|
// Étape 2: Connexion à l'API (25%)
|
||||||
final apiResult = await loginAPI(username, password, type: type);
|
final apiResult = await loginAPI(username, password, type: type);
|
||||||
|
|
||||||
@@ -264,7 +261,13 @@ class UserRepository extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Étape 5: Traitement de toutes les autres données via DataLoadingService
|
// Étape 5: Traitement de toutes les autres données via DataLoadingService
|
||||||
|
try {
|
||||||
await DataLoadingService.instance.processLoginData(apiResult);
|
await DataLoadingService.instance.processLoginData(apiResult);
|
||||||
|
} catch (processingError) {
|
||||||
|
debugPrint('❌ Erreur lors du traitement des données: $processingError');
|
||||||
|
// On continue quand même car l'utilisateur est connecté
|
||||||
|
debugPrint('⚠️ Connexion réussie mais avec des données partielles');
|
||||||
|
}
|
||||||
|
|
||||||
debugPrint('✅ Connexion réussie');
|
debugPrint('✅ Connexion réussie');
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -72,237 +72,6 @@ class ApiService {
|
|||||||
return computation();
|
return computation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// === TOUTES LES MÉTHODES EXISTANTES RESTENT IDENTIQUES ===
|
|
||||||
|
|
||||||
// Détermine l'environnement actuel (DEV, REC, PROD) en fonction de l'URL
|
|
||||||
String _determineEnvironment() {
|
|
||||||
if (!kIsWeb) {
|
|
||||||
// En mode non-web, utiliser l'environnement de développement par défaut
|
|
||||||
return 'DEV';
|
|
||||||
}
|
|
||||||
|
|
||||||
final currentUrl = html.window.location.href.toLowerCase();
|
|
||||||
|
|
||||||
if (currentUrl.contains('dapp.geosector.fr')) {
|
|
||||||
return 'DEV';
|
|
||||||
} else if (currentUrl.contains('rapp.geosector.fr')) {
|
|
||||||
return 'REC';
|
|
||||||
} else {
|
|
||||||
return 'PROD';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure l'URL de base API et l'identifiant d'application selon l'environnement
|
|
||||||
void _configureEnvironment() {
|
|
||||||
final env = _determineEnvironment();
|
|
||||||
|
|
||||||
switch (env) {
|
|
||||||
case 'DEV':
|
|
||||||
_baseUrl = AppKeys.baseApiUrlDev;
|
|
||||||
_appIdentifier = AppKeys.appIdentifierDev;
|
|
||||||
break;
|
|
||||||
case 'REC':
|
|
||||||
_baseUrl = AppKeys.baseApiUrlRec;
|
|
||||||
_appIdentifier = AppKeys.appIdentifierRec;
|
|
||||||
break;
|
|
||||||
default: // PROD
|
|
||||||
_baseUrl = AppKeys.baseApiUrlProd;
|
|
||||||
_appIdentifier = AppKeys.appIdentifierProd;
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint('GEOSECTOR 🔗 Environnement: $env, API: $_baseUrl');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Définir l'ID de session
|
|
||||||
void setSessionId(String? sessionId) {
|
|
||||||
_sessionId = sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtenir l'environnement actuel (utile pour le débogage)
|
|
||||||
String getCurrentEnvironment() {
|
|
||||||
return _determineEnvironment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtenir l'URL API actuelle (utile pour le débogage)
|
|
||||||
String getCurrentApiUrl() {
|
|
||||||
return _baseUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtenir l'identifiant d'application actuel (utile pour le débogage)
|
|
||||||
String getCurrentAppIdentifier() {
|
|
||||||
return _appIdentifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier la connectivité réseau
|
|
||||||
Future<bool> hasInternetConnection() async {
|
|
||||||
final connectivityResult = await (Connectivity().checkConnectivity());
|
|
||||||
return connectivityResult != ConnectivityResult.none;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Méthode POST générique
|
|
||||||
Future<Response> post(String path, {dynamic data}) async {
|
|
||||||
try {
|
|
||||||
return await _dio.post(path, data: data);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Méthode GET générique
|
|
||||||
Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {
|
|
||||||
try {
|
|
||||||
return await _dio.get(path, queryParameters: queryParameters);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Méthode PUT générique
|
|
||||||
Future<Response> put(String path, {dynamic data}) async {
|
|
||||||
try {
|
|
||||||
return await _dio.put(path, data: data);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Méthode DELETE générique
|
|
||||||
Future<Response> delete(String path) async {
|
|
||||||
try {
|
|
||||||
return await _dio.delete(path);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authentification avec PHP session
|
|
||||||
Future<Map<String, dynamic>> login(String username, String password, {required String type}) async {
|
|
||||||
try {
|
|
||||||
final response = await _dio.post(AppKeys.loginEndpoint, data: {
|
|
||||||
'username': username,
|
|
||||||
'password': password,
|
|
||||||
'type': type, // Ajouter le type de connexion (user ou admin)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Vérifier la structure de la réponse
|
|
||||||
final data = response.data as Map<String, dynamic>;
|
|
||||||
final status = data['status'] as String?;
|
|
||||||
|
|
||||||
// Afficher le message en cas d'erreur
|
|
||||||
if (status != 'success') {
|
|
||||||
final message = data['message'] as String?;
|
|
||||||
debugPrint('Erreur d\'authentification: $message');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si le statut est 'success', récupérer le session_id
|
|
||||||
if (status == 'success' && data.containsKey('session_id')) {
|
|
||||||
final sessionId = data['session_id'];
|
|
||||||
// Définir la session pour les futures requêtes
|
|
||||||
if (sessionId != null) {
|
|
||||||
setSessionId(sessionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Déconnexion
|
|
||||||
Future<void> logout() async {
|
|
||||||
try {
|
|
||||||
if (_sessionId != null) {
|
|
||||||
await _dio.post(AppKeys.logoutEndpoint);
|
|
||||||
_sessionId = null;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// Même en cas d'erreur, on réinitialise la session
|
|
||||||
_sessionId = null;
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utilisateurs
|
|
||||||
Future<List<UserModel>> getUsers() async {
|
|
||||||
try {
|
|
||||||
final response = await retry(
|
|
||||||
() => _dio.get('/users'),
|
|
||||||
retryIf: (e) => e is SocketException || e is TimeoutException,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (response.data as List).map((json) => UserModel.fromJson(json)).toList();
|
|
||||||
} catch (e) {
|
|
||||||
// Gérer les erreurs
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<UserModel> getUserById(int id) async {
|
|
||||||
try {
|
|
||||||
final response = await _dio.get('/users/$id');
|
|
||||||
return UserModel.fromJson(response.data);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<UserModel> createUser(UserModel user) async {
|
|
||||||
try {
|
|
||||||
final response = await _dio.post('/users', data: user.toJson());
|
|
||||||
return UserModel.fromJson(response.data);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<UserModel> updateUser(UserModel user) async {
|
|
||||||
try {
|
|
||||||
final response = await _dio.put('/users/${user.id}', data: user.toJson());
|
|
||||||
return UserModel.fromJson(response.data);
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> deleteUser(String id) async {
|
|
||||||
try {
|
|
||||||
await _dio.delete('/users/$id');
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Espace réservé pour les futures méthodes de gestion des profils
|
|
||||||
|
|
||||||
// Espace réservé pour les futures méthodes de gestion des données
|
|
||||||
|
|
||||||
// Synchronisation en batch
|
|
||||||
Future<Map<String, dynamic>> syncData({
|
|
||||||
List<UserModel>? users,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
final Map<String, dynamic> payload = {
|
|
||||||
if (users != null) 'users': users.map((u) => u.toJson()).toList(),
|
|
||||||
};
|
|
||||||
|
|
||||||
final response = await _dio.post('/sync', data: payload);
|
|
||||||
return response.data;
|
|
||||||
} catch (e) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Méthode de nettoyage pour les tests
|
|
||||||
static void reset() {
|
|
||||||
_instance = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final Dio _dio = Dio();
|
|
||||||
late final String _baseUrl;
|
|
||||||
late final String _appIdentifier;
|
|
||||||
String? _sessionId;
|
|
||||||
|
|
||||||
// Détermine l'environnement actuel (DEV, REC, PROD) en fonction de l'URL
|
// Détermine l'environnement actuel (DEV, REC, PROD) en fonction de l'URL
|
||||||
String _determineEnvironment() {
|
String _determineEnvironment() {
|
||||||
if (!kIsWeb) {
|
if (!kIsWeb) {
|
||||||
@@ -502,10 +271,6 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Espace réservé pour les futures méthodes de gestion des profils
|
|
||||||
|
|
||||||
// Espace réservé pour les futures méthodes de gestion des données
|
|
||||||
|
|
||||||
// Synchronisation en batch
|
// Synchronisation en batch
|
||||||
Future<Map<String, dynamic>> syncData({
|
Future<Map<String, dynamic>> syncData({
|
||||||
List<UserModel>? users,
|
List<UserModel>? users,
|
||||||
@@ -521,4 +286,9 @@ class ApiService {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Méthode de nettoyage pour les tests
|
||||||
|
static void reset() {
|
||||||
|
_instance = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,135 +53,67 @@ class DataLoadingService extends ChangeNotifier {
|
|||||||
Box<MessageModel> get _chatMessageBox => Hive.box<MessageModel>(AppKeys.chatMessagesBoxName);
|
Box<MessageModel> get _chatMessageBox => Hive.box<MessageModel>(AppKeys.chatMessagesBoxName);
|
||||||
Box get _settingsBox => Hive.box(AppKeys.settingsBoxName);
|
Box get _settingsBox => Hive.box(AppKeys.settingsBoxName);
|
||||||
|
|
||||||
// === NETTOYAGE ET PRÉPARATION DES DONNÉES ===
|
|
||||||
|
|
||||||
/// Nettoie toutes les données avant le login
|
|
||||||
Future<void> cleanDataBeforeLogin() async {
|
|
||||||
try {
|
|
||||||
_updateLoadingState(LoadingState.initial.copyWith(
|
|
||||||
progress: 0.05,
|
|
||||||
message: 'Nettoyage des données...',
|
|
||||||
stepDescription: 'Suppression des données obsolètes',
|
|
||||||
));
|
|
||||||
|
|
||||||
debugPrint('🧹 Début du nettoyage des données avant login...');
|
|
||||||
|
|
||||||
// Étape 1: Nettoyage des boîtes non référencées (5%)
|
|
||||||
await _cleanNonDefinedBoxes();
|
|
||||||
|
|
||||||
// Étape 2: Nettoyage sécurisé des données (10%)
|
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
|
||||||
progress: 0.10,
|
|
||||||
stepDescription: 'Préparation du stockage local',
|
|
||||||
));
|
|
||||||
|
|
||||||
if (kIsWeb) {
|
|
||||||
await HiveWebFix.safeCleanHiveBoxes(excludeBoxes: [AppKeys.userBoxName]);
|
|
||||||
} else if (Platform.isIOS) {
|
|
||||||
await _cleanHiveFilesOnIOS();
|
|
||||||
} else if (Platform.isAndroid) {
|
|
||||||
await _cleanHiveFilesOnAndroid();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Étape 3: Recréation des boîtes (15%)
|
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
|
||||||
progress: 0.15,
|
|
||||||
stepDescription: 'Initialisation des bases de données',
|
|
||||||
));
|
|
||||||
|
|
||||||
await _clearAndRecreateBoxes();
|
|
||||||
await _initializeBoxes();
|
|
||||||
|
|
||||||
debugPrint('✅ Nettoyage des données terminé');
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('❌ Erreur lors du nettoyage des données: $e');
|
|
||||||
_updateLoadingState(LoadingState.error('Erreur lors du nettoyage: $e'));
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Traite toutes les données reçues de l'API lors du login
|
/// Traite toutes les données reçues de l'API lors du login
|
||||||
|
/// Les boxes sont déjà propres, on charge juste les données
|
||||||
Future<void> processLoginData(Map<String, dynamic> apiResult) async {
|
Future<void> processLoginData(Map<String, dynamic> apiResult) async {
|
||||||
try {
|
try {
|
||||||
debugPrint('📊 Début du traitement des données de login...');
|
debugPrint('📊 Début du chargement des données (boxes déjà propres)...');
|
||||||
|
|
||||||
// Étape 4: Traitement des clients (35%)
|
// Vérifier que les boxes sont ouvertes
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
_verifyBoxesAreOpen();
|
||||||
progress: 0.35,
|
|
||||||
stepDescription: 'Chargement des clients',
|
|
||||||
));
|
|
||||||
|
|
||||||
|
// Charger les données directement (les boxes sont vides et propres)
|
||||||
if (apiResult['clients'] != null) {
|
if (apiResult['clients'] != null) {
|
||||||
await _processClients(apiResult['clients']);
|
await _processClients(apiResult['clients']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Étape 5: Traitement des opérations (50%)
|
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
|
||||||
progress: 0.50,
|
|
||||||
stepDescription: 'Chargement des opérations',
|
|
||||||
));
|
|
||||||
|
|
||||||
if (apiResult['operations'] != null) {
|
if (apiResult['operations'] != null) {
|
||||||
await _processOperations(apiResult['operations']);
|
await _processOperations(apiResult['operations']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Étape 6: Traitement des secteurs (65%)
|
if (apiResult['secteurs'] != null) {
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
await _processSectors(apiResult['secteurs']);
|
||||||
progress: 0.65,
|
|
||||||
stepDescription: 'Chargement des secteurs',
|
|
||||||
));
|
|
||||||
|
|
||||||
if (apiResult['sectors'] != null) {
|
|
||||||
await _processSectors(apiResult['sectors']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Étape 7: Traitement des passages (75%)
|
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
|
||||||
progress: 0.75,
|
|
||||||
stepDescription: 'Chargement des passages',
|
|
||||||
));
|
|
||||||
|
|
||||||
if (apiResult['passages'] != null) {
|
if (apiResult['passages'] != null) {
|
||||||
await _processPassages(apiResult['passages']);
|
await _processPassages(apiResult['passages']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Étape 8: Traitement des membres (85%)
|
if (apiResult['amicale'] != null) {
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
await _processAmicale(apiResult['amicale']);
|
||||||
progress: 0.85,
|
}
|
||||||
stepDescription: 'Chargement des membres',
|
if (apiResult['membres'] != null) {
|
||||||
));
|
await _processMembres(apiResult['membres']);
|
||||||
|
|
||||||
final membresData = apiResult['membres'] ?? apiResult['members'];
|
|
||||||
if (membresData != null) {
|
|
||||||
await _processMembres(membresData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Étape 9: Traitement des associations utilisateurs-secteurs (95%)
|
if (apiResult['userSecteurs'] != null) {
|
||||||
_updateLoadingState(_loadingState.copyWith(
|
await _processUserSectors(apiResult['userSecteurs']);
|
||||||
progress: 0.95,
|
|
||||||
stepDescription: 'Finalisation du chargement',
|
|
||||||
));
|
|
||||||
|
|
||||||
if (apiResult['users_sectors'] != null) {
|
|
||||||
await _processUserSectors(apiResult['users_sectors']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Étape finale: Chargement terminé (100%)
|
|
||||||
_updateLoadingState(LoadingState.completed.copyWith(
|
|
||||||
progress: 1.0,
|
|
||||||
message: 'Chargement terminé avec succès',
|
|
||||||
stepDescription: 'Données synchronisées',
|
|
||||||
));
|
|
||||||
|
|
||||||
debugPrint('✅ Traitement des données de login terminé');
|
|
||||||
_logDataSummary();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('❌ Erreur lors du traitement des données de login: $e');
|
debugPrint('❌ Erreur lors du chargement: $e');
|
||||||
_updateLoadingState(LoadingState.error('Erreur lors du chargement: $e'));
|
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _verifyBoxesAreOpen() {
|
||||||
|
final requiredBoxes = [
|
||||||
|
AppKeys.operationsBoxName,
|
||||||
|
AppKeys.sectorsBoxName,
|
||||||
|
AppKeys.passagesBoxName,
|
||||||
|
AppKeys.membresBoxName,
|
||||||
|
AppKeys.userSectorBoxName,
|
||||||
|
AppKeys.amicaleBoxName,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (final boxName in requiredBoxes) {
|
||||||
|
if (!Hive.isBoxOpen(boxName)) {
|
||||||
|
throw Exception('La boîte $boxName n\'est pas ouverte. Redémarrez l\'application.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint('✅ Toutes les boîtes requises sont ouvertes');
|
||||||
|
}
|
||||||
|
|
||||||
/// Nettoie complètement toutes les données lors du logout
|
/// Nettoie complètement toutes les données lors du logout
|
||||||
Future<void> cleanDataAfterLogout() async {
|
Future<void> cleanDataAfterLogout() async {
|
||||||
try {
|
try {
|
||||||
@@ -194,117 +126,6 @@ class DataLoadingService extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === MÉTHODES PRIVÉES DE NETTOYAGE ===
|
|
||||||
|
|
||||||
Future<void> _cleanNonDefinedBoxes() async {
|
|
||||||
final nonDefinedBoxes = ['auth', 'locations', 'messages'];
|
|
||||||
for (final boxName in nonDefinedBoxes) {
|
|
||||||
try {
|
|
||||||
if (Hive.isBoxOpen(boxName)) {
|
|
||||||
debugPrint('Fermeture de la boîte non référencée: $boxName');
|
|
||||||
await Hive.box(boxName).close();
|
|
||||||
}
|
|
||||||
await Hive.deleteBoxFromDisk(boxName);
|
|
||||||
debugPrint('✅ Box $boxName supprimée');
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('⚠️ Erreur suppression box $boxName: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _clearAndRecreateBoxes() async {
|
|
||||||
try {
|
|
||||||
debugPrint('🔄 Recréation des boîtes Hive...');
|
|
||||||
|
|
||||||
final boxesToDelete = [
|
|
||||||
AppKeys.passagesBoxName,
|
|
||||||
AppKeys.operationsBoxName,
|
|
||||||
AppKeys.sectorsBoxName,
|
|
||||||
AppKeys.userSectorBoxName,
|
|
||||||
AppKeys.chatConversationsBoxName,
|
|
||||||
AppKeys.chatMessagesBoxName,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Vider chaque boîte sans la fermer
|
|
||||||
for (final boxName in boxesToDelete) {
|
|
||||||
try {
|
|
||||||
if (Hive.isBoxOpen(boxName)) {
|
|
||||||
final box = Hive.box(boxName);
|
|
||||||
await box.clear();
|
|
||||||
debugPrint('✅ Box $boxName vidée');
|
|
||||||
} else {
|
|
||||||
await Hive.deleteBoxFromDisk(boxName);
|
|
||||||
debugPrint('✅ Box $boxName supprimée du disque');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('⚠️ Erreur nettoyage box $boxName: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('❌ Erreur recréation des boîtes: $e');
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _initializeBoxes() async {
|
|
||||||
debugPrint('📦 Initialisation des boîtes Hive...');
|
|
||||||
|
|
||||||
final boxesToInit = [
|
|
||||||
AppKeys.operationsBoxName,
|
|
||||||
AppKeys.sectorsBoxName,
|
|
||||||
AppKeys.passagesBoxName,
|
|
||||||
AppKeys.membresBoxName,
|
|
||||||
AppKeys.userSectorBoxName,
|
|
||||||
AppKeys.chatConversationsBoxName,
|
|
||||||
AppKeys.chatMessagesBoxName,
|
|
||||||
];
|
|
||||||
|
|
||||||
for (final boxName in boxesToInit) {
|
|
||||||
await _ensureBoxIsOpen(boxName);
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint('✅ Toutes les boîtes Hive sont ouvertes');
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _ensureBoxIsOpen(String boxName) async {
|
|
||||||
try {
|
|
||||||
if (!Hive.isBoxOpen(boxName)) {
|
|
||||||
debugPrint('Ouverture de la boîte $boxName...');
|
|
||||||
|
|
||||||
switch (boxName) {
|
|
||||||
case AppKeys.passagesBoxName:
|
|
||||||
await Hive.openBox<PassageModel>(boxName);
|
|
||||||
break;
|
|
||||||
case AppKeys.operationsBoxName:
|
|
||||||
await Hive.openBox<OperationModel>(boxName);
|
|
||||||
break;
|
|
||||||
case AppKeys.sectorsBoxName:
|
|
||||||
await Hive.openBox<SectorModel>(boxName);
|
|
||||||
break;
|
|
||||||
case AppKeys.membresBoxName:
|
|
||||||
await Hive.openBox<MembreModel>(boxName);
|
|
||||||
break;
|
|
||||||
case AppKeys.userSectorBoxName:
|
|
||||||
await Hive.openBox<UserSectorModel>(boxName);
|
|
||||||
break;
|
|
||||||
case AppKeys.chatConversationsBoxName:
|
|
||||||
await Hive.openBox<ConversationModel>(boxName);
|
|
||||||
break;
|
|
||||||
case AppKeys.chatMessagesBoxName:
|
|
||||||
await Hive.openBox<MessageModel>(boxName);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
await Hive.openBox(boxName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('❌ Erreur ouverture box $boxName: $e');
|
|
||||||
throw Exception('Impossible d\'ouvrir la boîte $boxName: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === MÉTHODES DE TRAITEMENT DES DONNÉES ===
|
// === MÉTHODES DE TRAITEMENT DES DONNÉES ===
|
||||||
|
|
||||||
Future<void> _processClients(dynamic clientsData) async {
|
Future<void> _processClients(dynamic clientsData) async {
|
||||||
@@ -446,6 +267,33 @@ class DataLoadingService extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ajouter cette nouvelle méthode pour traiter l'amicale unique
|
||||||
|
Future<void> _processAmicale(dynamic amicaleData) async {
|
||||||
|
try {
|
||||||
|
debugPrint('🏢 Traitement de l\'amicale unique...');
|
||||||
|
|
||||||
|
if (amicaleData == null) {
|
||||||
|
debugPrint('ℹ️ Aucune donnée d\'amicale à traiter');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _amicaleBox.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Les données d'amicale sont un objet unique
|
||||||
|
final Map<String, dynamic> amicaleMap = Map<String, dynamic>.from(amicaleData as Map);
|
||||||
|
final amicale = AmicaleModel.fromJson(amicaleMap);
|
||||||
|
await _amicaleBox.put(amicale.id, amicale);
|
||||||
|
debugPrint('✅ Amicale stockée: ${amicale.name} (ID: ${amicale.id})');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('⚠️ Erreur traitement amicale: $e');
|
||||||
|
debugPrint('⚠️ Données reçues: $amicaleData');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur traitement amicale: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _processMembres(dynamic membresData) async {
|
Future<void> _processMembres(dynamic membresData) async {
|
||||||
try {
|
try {
|
||||||
debugPrint('👤 Traitement des membres...');
|
debugPrint('👤 Traitement des membres...');
|
||||||
@@ -625,41 +473,6 @@ class DataLoadingService extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === MÉTHODES UTILITAIRES ===
|
|
||||||
|
|
||||||
/// Affiche un résumé des données chargées
|
|
||||||
void _logDataSummary() {
|
|
||||||
try {
|
|
||||||
debugPrint('📊 === RÉSUMÉ DES DONNÉES CHARGÉES ===');
|
|
||||||
debugPrint('Opérations: ${_operationBox.length}');
|
|
||||||
debugPrint('Secteurs: ${_sectorBox.length}');
|
|
||||||
debugPrint('Passages: ${_passageBox.length}');
|
|
||||||
debugPrint('Membres: ${_membreBox.length}');
|
|
||||||
debugPrint('Associations User-Sector: ${_userSectorBox.length}');
|
|
||||||
debugPrint('Amicales: ${_amicaleBox.length}');
|
|
||||||
debugPrint('=================================');
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('⚠️ Erreur lors du résumé: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retourne un résumé des données pour l'UI
|
|
||||||
Map<String, int> getDataSummary() {
|
|
||||||
try {
|
|
||||||
return {
|
|
||||||
'operations': _operationBox.length,
|
|
||||||
'sectors': _sectorBox.length,
|
|
||||||
'passages': _passageBox.length,
|
|
||||||
'membres': _membreBox.length,
|
|
||||||
'userSectors': _userSectorBox.length,
|
|
||||||
'amicales': _amicaleBox.length,
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('⚠️ Erreur génération résumé: $e');
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === RESET POUR TESTS ===
|
// === RESET POUR TESTS ===
|
||||||
static void reset() {
|
static void reset() {
|
||||||
_instance = null;
|
_instance = null;
|
||||||
|
|||||||
65
app/lib/core/services/hive_adapters.dart
Normal file
65
app/lib/core/services/hive_adapters.dart
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/user_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/client_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/operation_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/sector_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/passage_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/membre_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/user_sector_model.dart';
|
||||||
|
import 'package:geosector_app/core/data/models/region_model.dart';
|
||||||
|
import 'package:geosector_app/chat/models/chat_adapters.dart';
|
||||||
|
|
||||||
|
class HiveAdapters {
|
||||||
|
/// Enregistre tous les TypeAdapters nécessaires
|
||||||
|
static void registerAll() {
|
||||||
|
// Modèles principaux
|
||||||
|
if (!Hive.isAdapterRegistered(0)) {
|
||||||
|
Hive.registerAdapter(UserModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(1)) {
|
||||||
|
Hive.registerAdapter(OperationModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(3)) {
|
||||||
|
Hive.registerAdapter(SectorModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(4)) {
|
||||||
|
Hive.registerAdapter(PassageModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(5)) {
|
||||||
|
Hive.registerAdapter(MembreModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(6)) {
|
||||||
|
Hive.registerAdapter(UserSectorModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(7)) {
|
||||||
|
Hive.registerAdapter(RegionModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(10)) {
|
||||||
|
Hive.registerAdapter(ClientModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(11)) {
|
||||||
|
Hive.registerAdapter(AmicaleModelAdapter());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chat adapters
|
||||||
|
if (!Hive.isAdapterRegistered(20)) {
|
||||||
|
Hive.registerAdapter(ConversationModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(21)) {
|
||||||
|
Hive.registerAdapter(MessageModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(22)) {
|
||||||
|
Hive.registerAdapter(ParticipantModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(23)) {
|
||||||
|
Hive.registerAdapter(AnonymousUserModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(24)) {
|
||||||
|
Hive.registerAdapter(AudienceTargetModelAdapter());
|
||||||
|
}
|
||||||
|
if (!Hive.isAdapterRegistered(25)) {
|
||||||
|
Hive.registerAdapter(NotificationSettingsAdapter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,22 +4,9 @@ import 'package:flutter/foundation.dart' show kIsWeb;
|
|||||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||||
import 'package:geosector_app/core/services/app_info_service.dart';
|
import 'package:geosector_app/core/services/app_info_service.dart';
|
||||||
import 'package:geosector_app/core/services/api_service.dart';
|
import 'package:geosector_app/core/services/api_service.dart';
|
||||||
import 'package:geosector_app/core/services/current_user_service.dart';
|
|
||||||
import 'package:geosector_app/core/services/current_amicale_service.dart';
|
|
||||||
import 'package:geosector_app/app.dart';
|
import 'package:geosector_app/app.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:geosector_app/core/data/models/user_model.dart';
|
import 'package:geosector_app/core/services/hive_adapters.dart';
|
||||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/client_model.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/operation_model.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/sector_model.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/passage_model.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/membre_model.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/user_sector_model.dart';
|
|
||||||
import 'package:geosector_app/core/data/models/region_model.dart';
|
|
||||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
|
||||||
import 'package:geosector_app/core/services/hive_reset_state_service.dart';
|
|
||||||
import 'package:geosector_app/chat/models/chat_adapters.dart';
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
// IMPORTANT: Configurer l'URL strategy pour éviter les # dans les URLs
|
// IMPORTANT: Configurer l'URL strategy pour éviter les # dans les URLs
|
||||||
@@ -31,13 +18,7 @@ void main() async {
|
|||||||
await _initializeServices();
|
await _initializeServices();
|
||||||
|
|
||||||
// Initialiser Hive avec gestion des erreurs
|
// Initialiser Hive avec gestion des erreurs
|
||||||
final hiveInitialized = await _initializeHive();
|
await _initializeHive();
|
||||||
|
|
||||||
// TEMPORAIREMENT: Ne pas marquer l'erreur pour éviter la redirection
|
|
||||||
// if (!hiveInitialized) {
|
|
||||||
// debugPrint('Incompatibilité détectée dans les données Hive. Marquage pour affichage du dialogue...');
|
|
||||||
// hiveResetStateService.markAsReset();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Configurer l'orientation de l'application (mobile uniquement)
|
// Configurer l'orientation de l'application (mobile uniquement)
|
||||||
if (!kIsWeb) {
|
if (!kIsWeb) {
|
||||||
@@ -71,185 +52,16 @@ Future<void> _initializeServices() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialise Hive et les adaptateurs
|
Future<void> _initializeHive() async {
|
||||||
Future<bool> _initializeHive() async {
|
|
||||||
try {
|
try {
|
||||||
// Initialiser Hive
|
|
||||||
await Hive.initFlutter();
|
await Hive.initFlutter();
|
||||||
|
|
||||||
// Enregistrer les adaptateurs Hive pour les modèles principaux
|
// Enregistrer tous les adapters
|
||||||
_registerHiveAdapters();
|
HiveAdapters.registerAll();
|
||||||
|
|
||||||
// Ouvrir uniquement les boîtes essentielles au démarrage
|
debugPrint('✅ Hive et TypeAdapters initialisés');
|
||||||
await _openEssentialHiveBoxes();
|
|
||||||
|
|
||||||
// Charger les données depuis Hive au démarrage
|
|
||||||
await CurrentUserService.instance.loadFromHive();
|
|
||||||
await CurrentAmicaleService.instance.loadFromHive();
|
|
||||||
debugPrint('✅ Données utilisateur/amicale chargées depuis Hive');
|
|
||||||
|
|
||||||
debugPrint('Hive initialisé avec succès');
|
|
||||||
return true;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de l\'initialisation de Hive: $e');
|
debugPrint('❌ Erreur Hive: $e');
|
||||||
return false;
|
rethrow;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enregistre tous les adaptateurs Hive
|
|
||||||
void _registerHiveAdapters() {
|
|
||||||
// Vérifier si les adaptateurs sont déjà enregistrés pour éviter les doublons
|
|
||||||
if (!Hive.isAdapterRegistered(0)) {
|
|
||||||
Hive.registerAdapter(UserModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(1)) {
|
|
||||||
Hive.registerAdapter(AmicaleModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(2)) {
|
|
||||||
Hive.registerAdapter(ClientModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(3)) {
|
|
||||||
Hive.registerAdapter(OperationModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(4)) {
|
|
||||||
Hive.registerAdapter(SectorModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(5)) {
|
|
||||||
Hive.registerAdapter(PassageModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(6)) {
|
|
||||||
Hive.registerAdapter(MembreModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(7)) {
|
|
||||||
Hive.registerAdapter(UserSectorModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(8)) {
|
|
||||||
Hive.registerAdapter(RegionModelAdapter());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modèles de chat
|
|
||||||
if (!Hive.isAdapterRegistered(9)) {
|
|
||||||
Hive.registerAdapter(ConversationModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(10)) {
|
|
||||||
Hive.registerAdapter(MessageModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(11)) {
|
|
||||||
Hive.registerAdapter(ParticipantModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(12)) {
|
|
||||||
Hive.registerAdapter(AnonymousUserModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(13)) {
|
|
||||||
Hive.registerAdapter(AudienceTargetModelAdapter());
|
|
||||||
}
|
|
||||||
if (!Hive.isAdapterRegistered(14)) {
|
|
||||||
Hive.registerAdapter(NotificationSettingsAdapter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ouvre les boîtes Hive essentielles avec migration users -> user
|
|
||||||
Future<void> _openEssentialHiveBoxes() async {
|
|
||||||
final boxesToOpen = [
|
|
||||||
{'name': AppKeys.userBoxName, 'type': 'UserModel'},
|
|
||||||
{'name': AppKeys.amicaleBoxName, 'type': 'AmicaleModel'},
|
|
||||||
{'name': AppKeys.clientsBoxName, 'type': 'ClientModel'},
|
|
||||||
{'name': AppKeys.settingsBoxName, 'type': 'dynamic'},
|
|
||||||
{'name': AppKeys.chatConversationsBoxName, 'type': 'ConversationModel'},
|
|
||||||
{'name': AppKeys.chatMessagesBoxName, 'type': 'MessageModel'},
|
|
||||||
];
|
|
||||||
|
|
||||||
// Logique de migration de l'ancienne box users vers user
|
|
||||||
try {
|
|
||||||
// Vérifier si l'ancienne box users existe
|
|
||||||
if (await _doesBoxExist(AppKeys.usersBoxNameOld)) {
|
|
||||||
debugPrint('🔄 Migration détectée: box users -> user');
|
|
||||||
|
|
||||||
// Ouvrir l'ancienne box
|
|
||||||
final oldBox = await Hive.openBox<UserModel>(AppKeys.usersBoxNameOld);
|
|
||||||
|
|
||||||
// Ouvrir la nouvelle box
|
|
||||||
final newBox = await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
|
||||||
|
|
||||||
// Migrer les données si la nouvelle box est vide
|
|
||||||
if (oldBox.isNotEmpty && newBox.isEmpty) {
|
|
||||||
debugPrint('📦 Migration des données users -> user...');
|
|
||||||
|
|
||||||
// Chercher l'utilisateur actuel dans l'ancienne box
|
|
||||||
final userData = oldBox.get('current_user') ?? oldBox.values.firstOrNull;
|
|
||||||
if (userData != null) {
|
|
||||||
await newBox.put('current_user', userData);
|
|
||||||
debugPrint('✅ Migration de users -> user réussie pour ${userData.email}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fermer et supprimer l'ancienne box
|
|
||||||
await oldBox.close();
|
|
||||||
await Hive.deleteBoxFromDisk(AppKeys.usersBoxNameOld);
|
|
||||||
debugPrint('🗑️ Ancienne box users supprimée');
|
|
||||||
} else {
|
|
||||||
// Ouvrir normalement la nouvelle box
|
|
||||||
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('⚠️ Erreur migration box users: $e');
|
|
||||||
// En cas d'erreur, ouvrir quand même la nouvelle box
|
|
||||||
try {
|
|
||||||
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
|
||||||
} catch (e2) {
|
|
||||||
debugPrint('❌ Impossible d\'ouvrir la box user: $e2');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ouvrir les autres boîtes
|
|
||||||
for (final box in boxesToOpen) {
|
|
||||||
try {
|
|
||||||
final boxName = box['name'] as String;
|
|
||||||
final boxType = box['type'] as String;
|
|
||||||
|
|
||||||
// Skip userBoxName car déjà traité dans la migration
|
|
||||||
if (boxName == AppKeys.userBoxName) continue;
|
|
||||||
|
|
||||||
// Vérifier si la boîte est déjà ouverte
|
|
||||||
if (Hive.isBoxOpen(boxName)) {
|
|
||||||
debugPrint('📦 Boîte $boxName déjà ouverte');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (boxType) {
|
|
||||||
case 'AmicaleModel':
|
|
||||||
await Hive.openBox<AmicaleModel>(boxName);
|
|
||||||
break;
|
|
||||||
case 'ClientModel':
|
|
||||||
await Hive.openBox<ClientModel>(boxName);
|
|
||||||
break;
|
|
||||||
case 'ConversationModel':
|
|
||||||
await Hive.openBox<ConversationModel>(boxName);
|
|
||||||
break;
|
|
||||||
case 'MessageModel':
|
|
||||||
await Hive.openBox<MessageModel>(boxName);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
await Hive.openBox(boxName);
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint('✅ Boîte $boxName ouverte avec succès');
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('❌ Erreur lors de l\'ouverture de la boîte ${box['name']}: $e');
|
|
||||||
// Ne pas lancer d'erreur, continuer avec les autres boîtes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vérifie si une box Hive existe sur le disque
|
|
||||||
Future<bool> _doesBoxExist(String boxName) async {
|
|
||||||
try {
|
|
||||||
// Tentative d'ouverture pour vérifier l'existence
|
|
||||||
final box = await Hive.openBox<UserModel>(boxName);
|
|
||||||
final exists = box.isNotEmpty;
|
|
||||||
await box.close();
|
|
||||||
return exists;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:geosector_app/core/services/api_service.dart';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||||
@@ -64,6 +65,9 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
|||||||
void _loadCurrentUser() {
|
void _loadCurrentUser() {
|
||||||
final currentUser = widget.userRepository.getCurrentUser();
|
final currentUser = widget.userRepository.getCurrentUser();
|
||||||
|
|
||||||
|
debugPrint('🔍 _loadCurrentUser - Utilisateur: ${currentUser?.username} (ID: ${currentUser?.id})');
|
||||||
|
debugPrint('🔍 _loadCurrentUser - fkEntite: ${currentUser?.fkEntite}');
|
||||||
|
|
||||||
if (currentUser == null) {
|
if (currentUser == null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_errorMessage = 'Utilisateur non connecté';
|
_errorMessage = 'Utilisateur non connecté';
|
||||||
@@ -78,43 +82,16 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vérifier immédiatement si l'amicale existe
|
||||||
|
final amicale = widget.amicaleRepository.getUserAmicale(currentUser.fkEntite!);
|
||||||
|
debugPrint('🔍 Amicale trouvée dans le repository: ${amicale?.name ?? 'null'}');
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_currentUser = currentUser;
|
_currentUser = currentUser;
|
||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleEditAmicale(AmicaleModel amicale) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text('Modifier l\'amicale'),
|
|
||||||
content: Text('Voulez-vous modifier l\'amicale ${amicale.name} ?'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
child: const Text('Annuler'),
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
// TODO: Naviguer vers la page de modification
|
|
||||||
// Navigator.of(context).push(
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (context) => EditAmicalePage(
|
|
||||||
// amicale: amicale,
|
|
||||||
// amicaleRepository: widget.amicaleRepository,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
},
|
|
||||||
child: const Text('Modifier'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleEditMembre(MembreModel membre) {
|
void _handleEditMembre(MembreModel membre) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -226,9 +203,19 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
|||||||
child: ValueListenableBuilder<Box<AmicaleModel>>(
|
child: ValueListenableBuilder<Box<AmicaleModel>>(
|
||||||
valueListenable: widget.amicaleRepository.getAmicalesBox().listenable(),
|
valueListenable: widget.amicaleRepository.getAmicalesBox().listenable(),
|
||||||
builder: (context, amicalesBox, child) {
|
builder: (context, amicalesBox, child) {
|
||||||
|
debugPrint('🔍 AmicalesBox - Nombre d\'amicales: ${amicalesBox.length}');
|
||||||
|
debugPrint('🔍 AmicalesBox - Clés disponibles: ${amicalesBox.keys.toList()}');
|
||||||
|
debugPrint('🔍 Recherche amicale avec fkEntite: ${_currentUser!.fkEntite}');
|
||||||
|
|
||||||
final amicale = amicalesBox.get(_currentUser!.fkEntite!);
|
final amicale = amicalesBox.get(_currentUser!.fkEntite!);
|
||||||
|
debugPrint('🔍 Amicale récupérée: ${amicale?.name ?? 'AUCUNE'}');
|
||||||
|
|
||||||
if (amicale == null) {
|
if (amicale == null) {
|
||||||
|
// Ajouter plus d'informations de debug
|
||||||
|
debugPrint('❌ PROBLÈME: Amicale non trouvée');
|
||||||
|
debugPrint('❌ fkEntite recherché: ${_currentUser!.fkEntite}');
|
||||||
|
debugPrint('❌ Contenu de la box: ${amicalesBox.values.map((a) => '${a.id}: ${a.name}').join(', ')}');
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@@ -245,7 +232,7 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'L\'amicale associée à votre compte n\'existe plus.',
|
'L\'amicale associée à votre compte n\'existe plus.\nfkEntite: ${_currentUser!.fkEntite}',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: theme.textTheme.bodyLarge,
|
style: theme.textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
@@ -293,7 +280,7 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
|||||||
onDelete: null,
|
onDelete: null,
|
||||||
amicaleRepository: widget.amicaleRepository,
|
amicaleRepository: widget.amicaleRepository,
|
||||||
userRepository: widget.userRepository,
|
userRepository: widget.userRepository,
|
||||||
apiService: null, // Ou passez l'ApiService si vous l'avez disponible
|
apiService: ApiService.instance,
|
||||||
showActionsColumn: false,
|
showActionsColumn: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -68,10 +68,9 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Erreur lors de la récupération de la version: $e');
|
debugPrint('Erreur lors de la récupération de la version: $e');
|
||||||
// Fallback sur la version du AppInfoService si elle existe
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_appVersion = AppInfoService.fullVersion.split(' ').last; // Extraire juste le numéro
|
_appVersion = AppInfoService.fullVersion.split(' ').last;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,29 +80,24 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// Animation controller sur 5 secondes (augmenté de 3 à 5 secondes)
|
// Animation controller
|
||||||
_animationController = AnimationController(
|
_animationController = AnimationController(
|
||||||
vsync: this,
|
vsync: this,
|
||||||
duration: const Duration(seconds: 5),
|
duration: const Duration(seconds: 5),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Animation de 4x la taille à 1x la taille (augmenté de 3x à 4x)
|
|
||||||
_scaleAnimation = Tween<double>(
|
_scaleAnimation = Tween<double>(
|
||||||
begin: 4.0, // Commencer à 4x la taille
|
begin: 4.0,
|
||||||
end: 1.0, // Terminer à la taille normale
|
end: 1.0,
|
||||||
).animate(
|
).animate(
|
||||||
CurvedAnimation(
|
CurvedAnimation(
|
||||||
parent: _animationController,
|
parent: _animationController,
|
||||||
curve: Curves.easeOutBack, // Curve pour un effet de rebond
|
curve: Curves.easeOutBack,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Démarrer l'animation immédiatement
|
|
||||||
_animationController.forward();
|
_animationController.forward();
|
||||||
|
|
||||||
_getAppVersion();
|
_getAppVersion();
|
||||||
|
|
||||||
// Simuler le processus d'initialisation
|
|
||||||
_startInitialization();
|
_startInitialization();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,151 +108,337 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _startInitialization() async {
|
void _startInitialization() async {
|
||||||
// Étape 1: Initialisation des boîtes Hive (0% à 75%)
|
// Table rase complète et recréation propre
|
||||||
if (mounted) {
|
await _completeReset();
|
||||||
setState(() {
|
|
||||||
_statusMessage = "Initialisation des données...";
|
|
||||||
_progress = 0.0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialiser toutes les boîtes Hive
|
|
||||||
await _initializeAllHiveBoxes();
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
|
|
||||||
// Étape 2: Initialisation des services (75% à 100%)
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = "Préparation de l'application...";
|
|
||||||
_progress = 0.75;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_isInitializing = false;
|
|
||||||
_showButtons = true;
|
|
||||||
_progress = 1.0; // S'assurer que la barre est à 100%
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Méthode pour initialiser toutes les boîtes Hive
|
|
||||||
Future<void> _initializeAllHiveBoxes() async {
|
|
||||||
try {
|
|
||||||
debugPrint('Initialisation de toutes les boîtes Hive...');
|
|
||||||
|
|
||||||
// Structure pour les boîtes à ouvrir avec leurs noms d'affichage
|
|
||||||
final boxesToOpen = [
|
|
||||||
{'name': AppKeys.userBoxName, 'display': 'Préparation utilisateurs'},
|
|
||||||
{'name': AppKeys.amicaleBoxName, 'display': 'Préparation amicale'},
|
|
||||||
{'name': AppKeys.clientsBoxName, 'display': 'Préparation clients'},
|
|
||||||
{'name': AppKeys.regionsBoxName, 'display': 'Préparation régions'},
|
|
||||||
{'name': AppKeys.operationsBoxName, 'display': 'Préparation opérations'},
|
|
||||||
{'name': AppKeys.sectorsBoxName, 'display': 'Préparation secteurs'},
|
|
||||||
{'name': AppKeys.passagesBoxName, 'display': 'Préparation passages'},
|
|
||||||
{'name': AppKeys.membresBoxName, 'display': 'Préparation membres'},
|
|
||||||
{'name': AppKeys.userSectorBoxName, 'display': 'Préparation secteurs utilisateurs'},
|
|
||||||
{'name': AppKeys.settingsBoxName, 'display': 'Préparation paramètres'},
|
|
||||||
{'name': AppKeys.chatConversationsBoxName, 'display': 'Préparation conversations'},
|
|
||||||
{'name': AppKeys.chatMessagesBoxName, 'display': 'Préparation messages'},
|
|
||||||
];
|
|
||||||
|
|
||||||
// Calculer l'incrément de progression pour chaque boîte (0.75 / nombre de boîtes)
|
|
||||||
final progressIncrement = 0.75 / boxesToOpen.length;
|
|
||||||
double currentProgress = 0.0;
|
|
||||||
|
|
||||||
// Ouvrir chaque boîte si elle n'est pas déjà ouverte
|
|
||||||
for (int i = 0; i < boxesToOpen.length; i++) {
|
|
||||||
final boxName = boxesToOpen[i]['name'] as String;
|
|
||||||
final displayName = boxesToOpen[i]['display'] as String;
|
|
||||||
|
|
||||||
// Mettre à jour la barre de progression et le message
|
|
||||||
currentProgress = progressIncrement * (i + 1);
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = displayName;
|
|
||||||
_progress = currentProgress;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Hive.isBoxOpen(boxName)) {
|
|
||||||
debugPrint('Ouverture de la boîte $boxName ($displayName)...');
|
|
||||||
|
|
||||||
// Ouvrir la boîte avec le type approprié
|
|
||||||
if (boxName == AppKeys.userBoxName) {
|
|
||||||
await Hive.openBox<UserModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.amicaleBoxName) {
|
|
||||||
await Hive.openBox<AmicaleModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.clientsBoxName) {
|
|
||||||
await Hive.openBox<ClientModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.regionsBoxName) {
|
|
||||||
// Ouvrir la boîte des régions sans type spécifique pour l'instant
|
|
||||||
// car RegionModelAdapter n'est pas encore enregistré
|
|
||||||
await Hive.openBox(boxName);
|
|
||||||
} else if (boxName == AppKeys.operationsBoxName) {
|
|
||||||
await Hive.openBox<OperationModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.sectorsBoxName) {
|
|
||||||
await Hive.openBox<SectorModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.passagesBoxName) {
|
|
||||||
await Hive.openBox<PassageModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.membresBoxName) {
|
|
||||||
await Hive.openBox<MembreModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.userSectorBoxName) {
|
|
||||||
await Hive.openBox<UserSectorModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.chatConversationsBoxName) {
|
|
||||||
await Hive.openBox<ConversationModel>(boxName);
|
|
||||||
} else if (boxName == AppKeys.chatMessagesBoxName) {
|
|
||||||
await Hive.openBox<MessageModel>(boxName);
|
|
||||||
} else {
|
|
||||||
await Hive.openBox(boxName);
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint('Boîte $boxName ouverte avec succès');
|
|
||||||
} else {
|
|
||||||
debugPrint('Boîte $boxName déjà ouverte');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajouter une temporisation entre chaque ouverture
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mettre à jour la barre de progression à 0.2 (20%) à la fin
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = 'Toutes les boîtes sont prêtes';
|
|
||||||
_progress = 0.8;
|
|
||||||
});
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_statusMessage = "Préparation de l'application...";
|
|
||||||
_progress = 0.9;
|
|
||||||
});
|
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finalisation
|
// Finalisation
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
_statusMessage = "Application prête !";
|
||||||
|
_progress = 1.0;
|
||||||
_isInitializing = false;
|
_isInitializing = false;
|
||||||
_showButtons = true;
|
_showButtons = true;
|
||||||
_progress = 1.0;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
debugPrint('Toutes les boîtes Hive sont maintenant ouvertes');
|
}
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Erreur lors de l\'initialisation des boîtes Hive: $e');
|
/// RESET COMPLET : Destruction totale et recréation propre
|
||||||
|
Future<void> _completeReset() async {
|
||||||
|
try {
|
||||||
|
debugPrint('🧹 RESET COMPLET : Destruction totale des données Hive...');
|
||||||
|
|
||||||
|
// Étape 1: Sauvegarder les utilisateurs existants (optionnel)
|
||||||
|
Map<dynamic, UserModel>? existingUsers;
|
||||||
|
|
||||||
// En cas d'erreur, mettre à jour le message
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_statusMessage = 'Erreur lors de l\'initialisation des données';
|
_statusMessage = "Sauvegarde des utilisateurs...";
|
||||||
|
_progress = 0.05;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||||
|
final userBox = Hive.box<UserModel>(AppKeys.userBoxName);
|
||||||
|
existingUsers = Map.from(userBox.toMap());
|
||||||
|
debugPrint('📦 ${existingUsers.length} utilisateurs sauvegardés');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('⚠️ Erreur sauvegarde utilisateurs: $e');
|
||||||
|
existingUsers = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Étape 2: DESTRUCTION RADICALE - Fermer tout ce qui peut être ouvert
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_statusMessage = "Fermeture de toutes les bases de données...";
|
||||||
|
_progress = 0.15;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _closeAllKnownBoxes();
|
||||||
|
|
||||||
|
// Étape 3: DESTRUCTION RADICALE - Supprimer tout Hive du disque
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_statusMessage = "Suppression complète des anciennes données...";
|
||||||
|
_progress = 0.25;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _nukeHiveCompletely();
|
||||||
|
|
||||||
|
// Étape 4: RECRÉATION PROPRE
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_statusMessage = "Création des nouvelles bases de données...";
|
||||||
|
_progress = 0.40;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _createAllBoxesFresh();
|
||||||
|
|
||||||
|
// Étape 5: Restaurer les utilisateurs (optionnel)
|
||||||
|
if (existingUsers != null && existingUsers.isNotEmpty) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_statusMessage = "Restauration des utilisateurs...";
|
||||||
|
_progress = 0.80;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await _restoreUsers(existingUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Étape 6: Vérification finale
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_statusMessage = "Vérification des bases de données...";
|
||||||
|
_progress = 0.90;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint('✅ RESET COMPLET terminé avec succès');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur lors du reset complet: $e');
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_statusMessage = "Erreur critique - Redémarrage recommandé";
|
||||||
|
_progress = 1.0;
|
||||||
|
_isInitializing = false;
|
||||||
|
_showButtons = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ferme toutes les boîtes connues
|
||||||
|
Future<void> _closeAllKnownBoxes() async {
|
||||||
|
try {
|
||||||
|
final allKnownBoxes = [
|
||||||
|
AppKeys.userBoxName,
|
||||||
|
AppKeys.amicaleBoxName,
|
||||||
|
AppKeys.clientsBoxName,
|
||||||
|
AppKeys.regionsBoxName,
|
||||||
|
AppKeys.operationsBoxName,
|
||||||
|
AppKeys.sectorsBoxName,
|
||||||
|
AppKeys.passagesBoxName,
|
||||||
|
AppKeys.membresBoxName,
|
||||||
|
AppKeys.userSectorBoxName,
|
||||||
|
AppKeys.settingsBoxName,
|
||||||
|
AppKeys.chatConversationsBoxName,
|
||||||
|
AppKeys.chatMessagesBoxName,
|
||||||
|
// Boîtes potentiellement problématiques
|
||||||
|
'auth', 'locations', 'messages', 'temp'
|
||||||
|
];
|
||||||
|
|
||||||
|
debugPrint('🔒 Fermeture de ${allKnownBoxes.length} boîtes connues...');
|
||||||
|
|
||||||
|
for (final boxName in allKnownBoxes) {
|
||||||
|
try {
|
||||||
|
if (Hive.isBoxOpen(boxName)) {
|
||||||
|
await Hive.box(boxName).close();
|
||||||
|
debugPrint('✅ Boîte $boxName fermée');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('⚠️ Erreur fermeture $boxName: $e');
|
||||||
|
// Continuer même en cas d'erreur
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.delayed(const Duration(milliseconds: 1000));
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur fermeture des boîtes: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Suppression RADICALE de tout Hive
|
||||||
|
Future<void> _nukeHiveCompletely() async {
|
||||||
|
try {
|
||||||
|
debugPrint('💥 DESTRUCTION NUCLÉAIRE de Hive...');
|
||||||
|
|
||||||
|
if (kIsWeb) {
|
||||||
|
// En version web, supprimer toutes les boîtes possibles une par une
|
||||||
|
final allPossibleBoxes = [
|
||||||
|
AppKeys.userBoxName,
|
||||||
|
AppKeys.amicaleBoxName,
|
||||||
|
AppKeys.clientsBoxName,
|
||||||
|
AppKeys.regionsBoxName,
|
||||||
|
AppKeys.operationsBoxName,
|
||||||
|
AppKeys.sectorsBoxName,
|
||||||
|
AppKeys.passagesBoxName,
|
||||||
|
AppKeys.membresBoxName,
|
||||||
|
AppKeys.userSectorBoxName,
|
||||||
|
AppKeys.settingsBoxName,
|
||||||
|
AppKeys.chatConversationsBoxName,
|
||||||
|
AppKeys.chatMessagesBoxName,
|
||||||
|
// Toutes les boîtes potentiellement corrompues
|
||||||
|
'auth', 'locations', 'messages', 'temp', 'cache', 'data'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (final boxName in allPossibleBoxes) {
|
||||||
|
try {
|
||||||
|
await Hive.deleteBoxFromDisk(boxName);
|
||||||
|
debugPrint('✅ Boîte $boxName DÉTRUITE');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('⚠️ Erreur destruction $boxName: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Sur mobile/desktop, destruction totale
|
||||||
|
try {
|
||||||
|
await Hive.deleteFromDisk();
|
||||||
|
debugPrint('✅ Hive COMPLÈTEMENT DÉTRUIT');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('⚠️ Erreur destruction totale: $e');
|
||||||
|
// Fallback : supprimer boîte par boîte
|
||||||
|
await _deleteBoxesOneByOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attendre pour s'assurer que tout est détruit
|
||||||
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur destruction Hive: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fallback : supprimer les boîtes une par une
|
||||||
|
Future<void> _deleteBoxesOneByOne() async {
|
||||||
|
final allBoxes = [
|
||||||
|
AppKeys.userBoxName,
|
||||||
|
AppKeys.amicaleBoxName,
|
||||||
|
AppKeys.clientsBoxName,
|
||||||
|
AppKeys.regionsBoxName,
|
||||||
|
AppKeys.operationsBoxName,
|
||||||
|
AppKeys.sectorsBoxName,
|
||||||
|
AppKeys.passagesBoxName,
|
||||||
|
AppKeys.membresBoxName,
|
||||||
|
AppKeys.userSectorBoxName,
|
||||||
|
AppKeys.settingsBoxName,
|
||||||
|
AppKeys.chatConversationsBoxName,
|
||||||
|
AppKeys.chatMessagesBoxName,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (final boxName in allBoxes) {
|
||||||
|
try {
|
||||||
|
await Hive.deleteBoxFromDisk(boxName);
|
||||||
|
debugPrint('✅ Boîte $boxName supprimée (fallback)');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('⚠️ Erreur suppression fallback $boxName: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recrée toutes les boîtes VIDES et PROPRES
|
||||||
|
Future<void> _createAllBoxesFresh() async {
|
||||||
|
try {
|
||||||
|
debugPrint('🆕 Création de toutes les boîtes vides...');
|
||||||
|
|
||||||
|
final boxesToCreate = [
|
||||||
|
{'name': AppKeys.userBoxName, 'type': 'UserModel'},
|
||||||
|
{'name': AppKeys.amicaleBoxName, 'type': 'AmicaleModel'},
|
||||||
|
{'name': AppKeys.clientsBoxName, 'type': 'ClientModel'},
|
||||||
|
{'name': AppKeys.regionsBoxName, 'type': 'dynamic'},
|
||||||
|
{'name': AppKeys.operationsBoxName, 'type': 'OperationModel'},
|
||||||
|
{'name': AppKeys.sectorsBoxName, 'type': 'SectorModel'},
|
||||||
|
{'name': AppKeys.passagesBoxName, 'type': 'PassageModel'},
|
||||||
|
{'name': AppKeys.membresBoxName, 'type': 'MembreModel'},
|
||||||
|
{'name': AppKeys.userSectorBoxName, 'type': 'UserSectorModel'},
|
||||||
|
{'name': AppKeys.settingsBoxName, 'type': 'dynamic'},
|
||||||
|
{'name': AppKeys.chatConversationsBoxName, 'type': 'ConversationModel'},
|
||||||
|
{'name': AppKeys.chatMessagesBoxName, 'type': 'MessageModel'},
|
||||||
|
];
|
||||||
|
|
||||||
|
final progressIncrement = 0.35 / boxesToCreate.length; // De 0.40 à 0.75
|
||||||
|
|
||||||
|
for (int i = 0; i < boxesToCreate.length; i++) {
|
||||||
|
final boxInfo = boxesToCreate[i];
|
||||||
|
final boxName = boxInfo['name'] as String;
|
||||||
|
final boxType = boxInfo['type'] as String;
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_statusMessage = "Création de $boxName...";
|
||||||
|
_progress = 0.40 + (progressIncrement * i);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Créer la boîte avec le bon type
|
||||||
|
switch (boxType) {
|
||||||
|
case 'UserModel':
|
||||||
|
await Hive.openBox<UserModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'AmicaleModel':
|
||||||
|
await Hive.openBox<AmicaleModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'ClientModel':
|
||||||
|
await Hive.openBox<ClientModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'OperationModel':
|
||||||
|
await Hive.openBox<OperationModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'SectorModel':
|
||||||
|
await Hive.openBox<SectorModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'PassageModel':
|
||||||
|
await Hive.openBox<PassageModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'MembreModel':
|
||||||
|
await Hive.openBox<MembreModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'UserSectorModel':
|
||||||
|
await Hive.openBox<UserSectorModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'ConversationModel':
|
||||||
|
await Hive.openBox<ConversationModel>(boxName);
|
||||||
|
break;
|
||||||
|
case 'MessageModel':
|
||||||
|
await Hive.openBox<MessageModel>(boxName);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
await Hive.openBox(boxName);
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint('✅ Boîte $boxName créée (type: $boxType)');
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur création $boxName: $e');
|
||||||
|
// En cas d'erreur, essayer sans type
|
||||||
|
try {
|
||||||
|
await Hive.openBox(boxName);
|
||||||
|
debugPrint('⚠️ Boîte $boxName créée sans type');
|
||||||
|
} catch (e2) {
|
||||||
|
debugPrint('❌ Échec total création $boxName: $e2');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur création des boîtes: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restaure les utilisateurs sauvegardés
|
||||||
|
Future<void> _restoreUsers(Map<dynamic, UserModel> users) async {
|
||||||
|
try {
|
||||||
|
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||||
|
final userBox = Hive.box<UserModel>(AppKeys.userBoxName);
|
||||||
|
|
||||||
|
for (final entry in users.entries) {
|
||||||
|
try {
|
||||||
|
await userBox.put(entry.key, entry.value);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('⚠️ Erreur restauration utilisateur ${entry.key}: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint('✅ ${users.length} utilisateurs restaurés');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur restauration utilisateurs: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +475,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
children: [
|
children: [
|
||||||
const Spacer(flex: 2),
|
const Spacer(flex: 2),
|
||||||
|
|
||||||
// Logo avec animation de réduction
|
// Logo avec animation
|
||||||
AnimatedBuilder(
|
AnimatedBuilder(
|
||||||
animation: _scaleAnimation,
|
animation: _scaleAnimation,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
@@ -306,13 +486,13 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
},
|
},
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/images/logo-geosector-1024.png',
|
'assets/images/logo-geosector-1024.png',
|
||||||
height: 180, // Augmenté de 140 à 180
|
height: 180,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
// Titre avec animation fade-in
|
// Titre
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
opacity: _isInitializing ? 0.9 : 1.0,
|
opacity: _isInitializing ? 0.9 : 1.0,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
@@ -328,7 +508,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Sous-titre avec nouveau slogan
|
// Sous-titre
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
opacity: _isInitializing ? 0.8 : 1.0,
|
opacity: _isInitializing ? 0.8 : 1.0,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
@@ -356,7 +536,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
valueColor: AlwaysStoppedAnimation<Color>(
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
theme.colorScheme.primary,
|
theme.colorScheme.primary,
|
||||||
),
|
),
|
||||||
minHeight: 10, // Augmenté de 6 à 10
|
minHeight: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -369,7 +549,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
// Boutons après l'initialisation
|
// Boutons (reste identique)
|
||||||
if (_showButtons) ...[
|
if (_showButtons) ...[
|
||||||
// Bouton Connexion Utilisateur
|
// Bouton Connexion Utilisateur
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
@@ -377,7 +557,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/login/user'); // Utiliser la route spécifique
|
context.go('/login/user');
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.green,
|
backgroundColor: Colors.green,
|
||||||
@@ -402,13 +582,13 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Bouton Connexion Administrateur
|
// Bouton Connexion Administrateur
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
opacity: _showButtons ? 1.0 : 0.0,
|
opacity: _showButtons ? 1.0 : 0.0,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/login/admin'); // Utiliser la route spécifique
|
context.go('/login/admin');
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
@@ -432,7 +612,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 32), // 2 espaces sous le bouton précédent
|
const SizedBox(height: 32),
|
||||||
|
|
||||||
// Bouton d'inscription
|
// Bouton d'inscription
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
@@ -472,7 +652,6 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// Déterminer l'URL du site web en fonction de l'environnement
|
|
||||||
String webUrl = 'https://geosector.fr';
|
String webUrl = 'https://geosector.fr';
|
||||||
|
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
@@ -486,7 +665,6 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ouvrir l'URL dans une nouvelle fenêtre/onglet
|
|
||||||
launchUrl(
|
launchUrl(
|
||||||
Uri.parse(webUrl),
|
Uri.parse(webUrl),
|
||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
@@ -514,7 +692,8 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Badge de version en bas à droite
|
|
||||||
|
// Badge de version
|
||||||
if (_appVersion.isNotEmpty)
|
if (_appVersion.isNotEmpty)
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 16,
|
bottom: 16,
|
||||||
|
|||||||
@@ -98,14 +98,23 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
|||||||
|
|
||||||
// Appeler l'API pour mettre à jour l'entité
|
// Appeler l'API pour mettre à jour l'entité
|
||||||
Future<void> _updateAmicale(AmicaleModel amicale) async {
|
Future<void> _updateAmicale(AmicaleModel amicale) async {
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Afficher un indicateur de chargement
|
// Afficher un indicateur de chargement
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return const Center(
|
return const AlertDialog(
|
||||||
child: CircularProgressIndicator(),
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
CircularProgressIndicator(),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Text('Mise à jour en cours...'),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -121,9 +130,9 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
|||||||
'phone': amicale.phone,
|
'phone': amicale.phone,
|
||||||
'mobile': amicale.mobile,
|
'mobile': amicale.mobile,
|
||||||
'email': amicale.email,
|
'email': amicale.email,
|
||||||
'chk_copie_mail_recu': amicale.chkCopieMailRecu,
|
'chk_copie_mail_recu': amicale.chkCopieMailRecu ? 1 : 0,
|
||||||
'chk_accept_sms': amicale.chkAcceptSms,
|
'chk_accept_sms': amicale.chkAcceptSms ? 1 : 0,
|
||||||
'chk_stripe': amicale.chkStripe,
|
'chk_stripe': amicale.chkStripe ? 1 : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ajouter les champs réservés aux administrateurs si l'utilisateur est admin
|
// Ajouter les champs réservés aux administrateurs si l'utilisateur est admin
|
||||||
@@ -132,63 +141,81 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
|||||||
data['gps_lat'] = amicale.gpsLat;
|
data['gps_lat'] = amicale.gpsLat;
|
||||||
data['gps_lng'] = amicale.gpsLng;
|
data['gps_lng'] = amicale.gpsLng;
|
||||||
data['stripe_id'] = amicale.stripeId;
|
data['stripe_id'] = amicale.stripeId;
|
||||||
data['chk_demo'] = amicale.chkDemo;
|
data['chk_demo'] = amicale.chkDemo ? 1 : 0;
|
||||||
data['chk_active'] = amicale.chkActive;
|
data['chk_active'] = amicale.chkActive ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fermer l'indicateur de chargement
|
debugPrint('🔧 Données à envoyer à l\'API: $data');
|
||||||
Navigator.of(context).pop();
|
|
||||||
|
bool apiSuccess = false;
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
// Appeler l'API si le service est disponible
|
// Appeler l'API si le service est disponible
|
||||||
if (widget.apiService != null) {
|
if (widget.apiService != null) {
|
||||||
try {
|
try {
|
||||||
await widget.apiService!.post('/entite/update', data: data);
|
debugPrint('📡 Appel API pour mise à jour amicale...');
|
||||||
|
|
||||||
// Afficher un message de succès
|
// Version RESTful correcte avec PUT
|
||||||
if (mounted) {
|
final response = await widget.apiService!.put('/entites/${amicale.id}', data: data);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
// Alternative avec PATCH si votre API le supporte
|
||||||
content: Text('Amicale mise à jour avec succès'),
|
// final response = await widget.apiService!.patch('/entites/${amicale.id}', data: data);
|
||||||
backgroundColor: Colors.green,
|
|
||||||
),
|
debugPrint('📡 Réponse API: ${response.statusCode}');
|
||||||
);
|
|
||||||
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
|
apiSuccess = true;
|
||||||
|
} else {
|
||||||
|
errorMessage = 'Erreur serveur: ${response.statusCode}';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Afficher un message d'erreur
|
debugPrint('❌ Erreur API: $error');
|
||||||
if (mounted) {
|
errorMessage = 'Erreur lors de la communication avec le serveur: $error';
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text('Erreur lors de la mise à jour de l\'amicale: $error'),
|
|
||||||
backgroundColor: Colors.red,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return; // Sortir de la fonction en cas d'erreur
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Pas d'API service, afficher un message d'information
|
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
const SnackBar(
|
|
||||||
content: Text('Modifications enregistrées localement'),
|
|
||||||
backgroundColor: Colors.blue,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fermer l'indicateur de chargement
|
||||||
|
if (mounted && Navigator.of(context).canPop()) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
if (apiSuccess) {
|
||||||
// Appeler la fonction onSubmit si elle existe
|
// Appeler la fonction onSubmit si elle existe
|
||||||
if (widget.onSubmit != null) {
|
if (widget.onSubmit != null) {
|
||||||
widget.onSubmit!(amicale);
|
widget.onSubmit!(amicale);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fermer le formulaire
|
// Afficher un message de succès
|
||||||
if (mounted) {
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(widget.apiService != null ? 'Amicale mise à jour avec succès' : 'Modifications enregistrées localement'),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fermer le formulaire après un délai pour que l'utilisateur voie le message
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
|
||||||
|
if (mounted && Navigator.of(context).canPop()) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Afficher un message d'erreur
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(errorMessage ?? 'Erreur lors de la mise à jour'),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
duration: const Duration(seconds: 4),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
debugPrint('❌ Erreur générale dans _updateAmicale: $e');
|
||||||
|
|
||||||
// Fermer l'indicateur de chargement si encore ouvert
|
// Fermer l'indicateur de chargement si encore ouvert
|
||||||
if (Navigator.of(context).canPop()) {
|
if (mounted && Navigator.of(context).canPop()) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,8 +223,9 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
|||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Erreur: ${e.toString()}'),
|
content: Text('Erreur inattendue: ${e.toString()}'),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
|
duration: const Duration(seconds: 4),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -205,9 +233,14 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _submitForm() {
|
void _submitForm() {
|
||||||
|
debugPrint('🔧 _submitForm appelée');
|
||||||
|
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
|
debugPrint('🔧 Formulaire valide');
|
||||||
|
|
||||||
// Vérifier qu'au moins un numéro de téléphone est renseigné
|
// Vérifier qu'au moins un numéro de téléphone est renseigné
|
||||||
if (_phoneController.text.isEmpty && _mobileController.text.isEmpty) {
|
if (_phoneController.text.isEmpty && _mobileController.text.isEmpty) {
|
||||||
|
debugPrint('⚠️ Aucun numéro de téléphone renseigné');
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Veuillez renseigner au moins un numéro de téléphone'),
|
content: Text('Veuillez renseigner au moins un numéro de téléphone'),
|
||||||
@@ -217,6 +250,8 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debugPrint('🔧 Création de l\'objet AmicaleModel...');
|
||||||
|
|
||||||
final amicale = widget.amicale?.copyWith(
|
final amicale = widget.amicale?.copyWith(
|
||||||
name: _nameController.text,
|
name: _nameController.text,
|
||||||
adresse1: _adresse1Controller.text,
|
adresse1: _adresse1Controller.text,
|
||||||
@@ -258,10 +293,13 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
|||||||
chkActive: _chkActive,
|
chkActive: _chkActive,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
debugPrint('🔧 AmicaleModel créé: ${amicale.name}');
|
||||||
|
debugPrint('🔧 Appel de _updateAmicale...');
|
||||||
|
|
||||||
// Appeler l'API pour mettre à jour l'amicale
|
// Appeler l'API pour mettre à jour l'amicale
|
||||||
_updateAmicale(amicale);
|
_updateAmicale(amicale);
|
||||||
|
} else {
|
||||||
// Ne pas appeler widget.onSubmit ici car c'est fait dans _updateAmicale
|
debugPrint('❌ Formulaire invalide');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class AmicaleTableWidget extends StatelessWidget {
|
|||||||
final Function(AmicaleModel)? onDelete;
|
final Function(AmicaleModel)? onDelete;
|
||||||
final AmicaleRepository amicaleRepository;
|
final AmicaleRepository amicaleRepository;
|
||||||
final UserRepository userRepository; // Nouveau paramètre
|
final UserRepository userRepository; // Nouveau paramètre
|
||||||
final ApiService? apiService; // Nouveau paramètre optionnel
|
final ApiService? apiService;
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
final String? emptyMessage;
|
final String? emptyMessage;
|
||||||
final bool readOnly;
|
final bool readOnly;
|
||||||
@@ -35,7 +35,7 @@ class AmicaleTableWidget extends StatelessWidget {
|
|||||||
required this.userRepository, // Requis
|
required this.userRepository, // Requis
|
||||||
this.onEdit,
|
this.onEdit,
|
||||||
this.onDelete,
|
this.onDelete,
|
||||||
this.apiService, // Optionnel
|
this.apiService,
|
||||||
this.isLoading = false,
|
this.isLoading = false,
|
||||||
this.emptyMessage,
|
this.emptyMessage,
|
||||||
this.readOnly = false,
|
this.readOnly = false,
|
||||||
@@ -83,9 +83,13 @@ class AmicaleTableWidget extends StatelessWidget {
|
|||||||
readOnly: false,
|
readOnly: false,
|
||||||
userRepository: userRepository,
|
userRepository: userRepository,
|
||||||
apiService: apiService,
|
apiService: apiService,
|
||||||
onSubmit: (updatedAmicale) {
|
onSubmit: (updatedAmicale) async {
|
||||||
|
// Sauvegarder l'amicale mise à jour dans le repository
|
||||||
|
debugPrint('🔄 Sauvegarde de l\'amicale mise à jour: ${updatedAmicale.name}');
|
||||||
|
await amicaleRepository.saveAmicale(updatedAmicale);
|
||||||
|
debugPrint('✅ Amicale sauvegardée dans le repository');
|
||||||
|
|
||||||
Navigator.of(dialogContext).pop();
|
Navigator.of(dialogContext).pop();
|
||||||
// La mise à jour sera gérée par les ValueListenableBuilder
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -227,7 +231,12 @@ class AmicaleTableWidget extends StatelessWidget {
|
|||||||
readOnly: true,
|
readOnly: true,
|
||||||
userRepository: userRepository,
|
userRepository: userRepository,
|
||||||
apiService: apiService,
|
apiService: apiService,
|
||||||
onSubmit: (updatedAmicale) {
|
onSubmit: (updatedAmicale) async {
|
||||||
|
// Sauvegarder l'amicale mise à jour dans le repository
|
||||||
|
debugPrint('🔄 Sauvegarde de l\'amicale mise à jour: ${updatedAmicale.name}');
|
||||||
|
await amicaleRepository.saveAmicale(updatedAmicale);
|
||||||
|
debugPrint('✅ Amicale sauvegardée dans le repository');
|
||||||
|
|
||||||
Navigator.of(dialogContext).pop();
|
Navigator.of(dialogContext).pop();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||||
import 'package:geosector_app/app.dart'; // Pour accéder à l'instance globale de ApiService
|
import 'package:geosector_app/core/services/api_service.dart'; // Import du service singleton
|
||||||
|
|
||||||
/// Widget de carte réutilisable utilisant Mapbox
|
/// Widget de carte réutilisable utilisant Mapbox
|
||||||
///
|
///
|
||||||
@@ -105,11 +105,10 @@ class _MapboxMapState extends State<MapboxMap> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Déterminer l'URL du template de tuiles Mapbox
|
// Déterminer l'URL du template de tuiles Mapbox
|
||||||
// Utiliser l'environnement actuel pour obtenir la bonne clé API
|
// Utiliser l'environnement actuel pour obtenir la bonne clé API
|
||||||
final String environment = apiService.getCurrentEnvironment();
|
final String environment = ApiService.instance.getCurrentEnvironment();
|
||||||
final String mapboxToken = AppKeys.getMapboxApiKey(environment);
|
final String mapboxToken = AppKeys.getMapboxApiKey(environment);
|
||||||
final String mapStyle = widget.mapStyle ?? 'mapbox/streets-v11';
|
final String mapStyle = widget.mapStyle ?? 'mapbox/streets-v11';
|
||||||
final String urlTemplate =
|
final String urlTemplate = 'https://api.mapbox.com/styles/v1/$mapStyle/tiles/256/{z}/{x}/{y}@2x?access_token=$mapboxToken';
|
||||||
'https://api.mapbox.com/styles/v1/$mapStyle/tiles/256/{z}/{x}/{y}@2x?access_token=$mapboxToken';
|
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
@@ -145,12 +144,10 @@ class _MapboxMapState extends State<MapboxMap> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Polygones
|
// Polygones
|
||||||
if (widget.polygons != null && widget.polygons!.isNotEmpty)
|
if (widget.polygons != null && widget.polygons!.isNotEmpty) PolygonLayer(polygons: widget.polygons!),
|
||||||
PolygonLayer(polygons: widget.polygons!),
|
|
||||||
|
|
||||||
// Marqueurs
|
// Marqueurs
|
||||||
if (widget.markers != null && widget.markers!.isNotEmpty)
|
if (widget.markers != null && widget.markers!.isNotEmpty) MarkerLayer(markers: widget.markers!),
|
||||||
MarkerLayer(markers: widget.markers!),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class MembreRowWidget extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
membre.firstName,
|
membre.firstName ?? '',
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -54,7 +54,7 @@ class MembreRowWidget extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 2,
|
flex: 2,
|
||||||
child: Text(
|
child: Text(
|
||||||
membre.name,
|
membre.name ?? '',
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -70,31 +70,31 @@ class MembreRowWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Rôle (fkRole)
|
// Rôle (role au lieu de fkRole)
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Text(
|
child: Text(
|
||||||
_getRoleName(membre.fkRole),
|
_getRoleName(membre.role),
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Statut (actif/inactif)
|
// Statut (isActive au lieu de chkActive)
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: membre.chkActive == 1 ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1),
|
color: membre.isActive ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: membre.chkActive == 1 ? Colors.green.withOpacity(0.3) : Colors.red.withOpacity(0.3),
|
color: membre.isActive ? Colors.green.withOpacity(0.3) : Colors.red.withOpacity(0.3),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
membre.chkActive == 1 ? 'Actif' : 'Inactif',
|
membre.isActive ? 'Actif' : 'Inactif',
|
||||||
style: theme.textTheme.bodySmall?.copyWith(
|
style: theme.textTheme.bodySmall?.copyWith(
|
||||||
color: membre.chkActive == 1 ? Colors.green[700] : Colors.red[700],
|
color: membre.isActive ? Colors.green[700] : Colors.red[700],
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
@@ -161,18 +161,20 @@ class MembreRowWidget extends StatelessWidget {
|
|||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder: (context) => AlertDialog(
|
||||||
title: Text('${membre.firstName} ${membre.name}'),
|
title: Text('${membre.firstName ?? ''} ${membre.name ?? ''}'),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildDetailRow('ID', membre.id.toString()),
|
_buildDetailRow('ID', membre.id.toString()),
|
||||||
_buildDetailRow('Email', membre.email),
|
_buildDetailRow('Email', membre.email),
|
||||||
_buildDetailRow('Username', membre.username),
|
_buildDetailRow('Username', membre.username ?? 'Non défini'),
|
||||||
_buildDetailRow('Rôle', _getRoleName(membre.fkRole)),
|
_buildDetailRow('Rôle', _getRoleName(membre.role)),
|
||||||
_buildDetailRow('Titre', membre.fkTitre.toString()),
|
_buildDetailRow('Titre', membre.fkTitre?.toString() ?? 'Non défini'),
|
||||||
_buildDetailRow('Secteur', membre.sectName ?? 'Non défini'),
|
_buildDetailRow('Secteur', membre.sectName ?? 'Non défini'),
|
||||||
_buildDetailRow('Statut', membre.chkActive == 1 ? 'Actif' : 'Inactif'),
|
_buildDetailRow('Statut', membre.isActive ? 'Actif' : 'Inactif'),
|
||||||
|
_buildDetailRow('Téléphone', membre.phone ?? 'Non défini'),
|
||||||
|
_buildDetailRow('Mobile', membre.mobile ?? 'Non défini'),
|
||||||
if (membre.dateNaissance != null)
|
if (membre.dateNaissance != null)
|
||||||
_buildDetailRow('Date de naissance', '${membre.dateNaissance!.day}/${membre.dateNaissance!.month}/${membre.dateNaissance!.year}'),
|
_buildDetailRow('Date de naissance', '${membre.dateNaissance!.day}/${membre.dateNaissance!.month}/${membre.dateNaissance!.year}'),
|
||||||
if (membre.dateEmbauche != null)
|
if (membre.dateEmbauche != null)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ Hive.registerAdapter(SectorModelAdapter());
|
|||||||
Hive.registerAdapter(PassageModelAdapter());
|
Hive.registerAdapter(PassageModelAdapter());
|
||||||
|
|
||||||
// Ouvrir les boîtes Hive
|
// Ouvrir les boîtes Hive
|
||||||
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
|
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
||||||
await Hive.openBox<OperationModel>(AppKeys.operationsBoxName);
|
await Hive.openBox<OperationModel>(AppKeys.operationsBoxName);
|
||||||
await Hive.openBox<SectorModel>(AppKeys.sectorsBoxName);
|
await Hive.openBox<SectorModel>(AppKeys.sectorsBoxName);
|
||||||
await Hive.openBox<PassageModel>(AppKeys.passagesBoxName);
|
await Hive.openBox<PassageModel>(AppKeys.passagesBoxName);
|
||||||
@@ -98,7 +98,7 @@ Hive.registerAdapter(SectorModelAdapter());
|
|||||||
Hive.registerAdapter(PassageModelAdapter());
|
Hive.registerAdapter(PassageModelAdapter());
|
||||||
|
|
||||||
// N'ouvrir que la boîte des utilisateurs au démarrage
|
// N'ouvrir que la boîte des utilisateurs au démarrage
|
||||||
await Hive.openBox<UserModel>(AppKeys.usersBoxName);
|
await Hive.openBox<UserModel>(AppKeys.userBoxName);
|
||||||
await Hive.openBox(AppKeys.settingsBoxName); // Préférences générales
|
await Hive.openBox(AppKeys.settingsBoxName); // Préférences générales
|
||||||
|
|
||||||
// Les autres boîtes seront ouvertes après connexion dans UserRepository.login()
|
// Les autres boîtes seront ouvertes après connexion dans UserRepository.login()
|
||||||
@@ -228,8 +228,8 @@ Future<bool> logout() async {
|
|||||||
Future<void> _deepCleanHiveBoxes() async {
|
Future<void> _deepCleanHiveBoxes() async {
|
||||||
try {
|
try {
|
||||||
// 1. Vider toutes les boîtes sans les fermer
|
// 1. Vider toutes les boîtes sans les fermer
|
||||||
if (Hive.isBoxOpen(AppKeys.usersBoxName)) {
|
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||||
await Hive.box<UserModel>(AppKeys.usersBoxName).clear();
|
await Hive.box<UserModel>(AppKeys.userBoxName).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Hive.isBoxOpen(AppKeys.operationsBoxName)) {
|
if (Hive.isBoxOpen(AppKeys.operationsBoxName)) {
|
||||||
@@ -336,7 +336,7 @@ Future<void> _ensureBoxIsOpen(String boxName) async {
|
|||||||
await Hive.openBox<OperationModel>(boxName);
|
await Hive.openBox<OperationModel>(boxName);
|
||||||
} else if (boxName == AppKeys.sectorsBoxName) {
|
} else if (boxName == AppKeys.sectorsBoxName) {
|
||||||
await Hive.openBox<SectorModel>(boxName);
|
await Hive.openBox<SectorModel>(boxName);
|
||||||
} else if (boxName == AppKeys.usersBoxName) {
|
} else if (boxName == AppKeys.userBoxName) {
|
||||||
await Hive.openBox<UserModel>(boxName);
|
await Hive.openBox<UserModel>(boxName);
|
||||||
} else {
|
} else {
|
||||||
await Hive.openBox(boxName);
|
await Hive.openBox(boxName);
|
||||||
|
|||||||
Reference in New Issue
Block a user