maintenant comment mettre en place le fait de mettre un aivs à des Utilisateurs si on à déjà répondu a une de leur annonce , il faut une nouvelle table ?: import 'package:sae_mobile/models/annonce.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

final SupabaseClient supabaseClient = Supabase.instance.client;

class AnnonceQueries {
  static Future<String> publishAnnonce(Annonce annonce) async {
    print("publishAnnonce");
    print(annonce.dateDeb.toIso8601String());
    print(annonce.dateFin.toIso8601String());
    print(annonce.titre);
    PostgrestList result = await supabaseClient.from('ANNONCES').insert({
      'titre': annonce.titre,
      'description': annonce.description,
      'dateDeb': annonce.dateDeb.toIso8601String(),
      'dateFin': annonce.dateFin.toIso8601String(),
      'idType': 1,
      'idEtat': 2,
    }).select('id');
    print("result");

    if (result.isEmpty) {
      throw Exception('Failed to create annonce');
    }

    String id = result[0]['id'];

    await supabaseClient.from('PUBLIE').insert({
      'id_a': id,
      'id_user': annonce.auteur.id,
    });

    return id;
  }

  static Future<PostgrestList> getAnnonces() async {
    final response = await supabaseClient.from('ANNONCES').select();
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnoncesByType(String id) async {
    final response =
        await supabaseClient.from('ANNONCES').select().eq('idType', id);
    if (response.isEmpty) {
      throw Exception('Aucune annonce de ce type');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceNonRepondu() async {
    final response =
        await supabaseClient.from('ANNONCES').select().eq('idEtat', 2);
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceRepondu(String id_u) async {
    final ids_a =
        await supabaseClient.from('REPONDS').select().eq('id_user', id_u);
    if (ids_a.isEmpty) {
      throw Exception("Pas d'annonces repondues");
    }
    final response = await supabaseClient
        .from('ANNONCES')
        .select()
        .inFilter('id', ids_a.map((e) => e['id_a']).toList());
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceCloturer(String id_u) async {
    final ids_a =
        await supabaseClient.from('REPONDS').select().eq('id_user', id_u);
    if (ids_a.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    final response = await supabaseClient.from('ANNONCES').select().inFilter(
        'id',
        ids_a.map((e) => e['id_a']).where((e) => e['id_etat'] == 3).toList());
    if (response.isEmpty) {
      throw Exception('Failed to get annonces');
    }
    return response;
  }

  static Future<PostgrestList> getAnnonceById(String id) async {
    final response =
        await supabaseClient.from('ANNONCES').select().eq('id', id);
    if (response.isEmpty) {
      throw Exception('Failed to get annonce');
    }
    return response;
  }

  static Future<String> getAuteurAnnonce(String id) async {
    final response =
        await supabaseClient.from('PUBLIE').select().eq('id_a', id);
    if (response.isEmpty) {
      throw Exception('Failed to get auteur');
    }
    return response[0]['id_user'];
  }

  static Future<void> accepterAnnonce(String id_a, String id_user) async {
    await supabaseClient.from('REPONDS').insert({
      'id_a': id_a,
      'id_user': id_user,
    });
  }

  static Future<void> updateAnnonceEtat(String id, int etat) async {
    await supabaseClient.from('ANNONCES').update({'idEtat': etat}).eq('id', id);
  }

  static Future<void> mettreAvis(String id_a, String id_u, String avis) async {
    await supabaseClient.from('AVIS').insert({
      'id_a': id_a,
      'id_user': id_u,
      'avis': avis,
    });
  }

  static Future<PostgrestList> getAnnonceAvis(String id_a) async {
    final response = await supabaseClient
        .from('AVIS')
        .select('avis, users:id_user (username)')
        .eq('id_a', id_a);
    if (response.isEmpty) {
      throw Exception('Failed to get avis');
    }
    return response;
  }
}
import 'package:sae_mobile/models/User.dart';
import 'package:sae_mobile/models/queries/distant/annonce.dart' as dist;
import 'package:sae_mobile/models/queries/local/annonce.dart' as local;

class Annonce {
  final String id;
  final String titre;
  final String description;
  final DateTime dateDeb;
  final DateTime dateFin;
  final User auteur;
  late final int etat;
  late AnnonceController controller;

  Annonce(this.id, this.titre, this.description, this.dateDeb, this.dateFin,
      this.auteur, this.etat) {
    switch (etat) {
      case 1:
        controller = AnnonceController(this, AnnonceNonPublie());
        break;
      case 2:
        controller = AnnonceController(this, AnnonceNonRepondu());
        break;
      case 3:
        controller = AnnonceController(this, AnnonceRepondu());
        break;
      case 4:
        controller = AnnonceController(this, AnnonceCloture());
        break;
    }
  }

  factory Annonce.fromJson(Map<String, dynamic> json, User auteur) {
    print(json);
    return Annonce(
      json['id'],
      json['titre'],
      json['description'],
      DateTime.parse(json['dateDeb']),
      DateTime.parse(json['dateFin']),
      auteur,
      json['idEtat'],
    );
  }

  void setEtat(int etat) {
    this.etat = etat;
  }

  void publier() {
    controller.publier();
  }

  void repondre(String id_u) {
    print(controller.etat);
    controller.repondre(id_u);
  }

  void cloturer() {
    controller.cloturer();
  }

  Future<void> mettreAvis(String id_u, String avis) async {
    controller.mettreAvis(id_u, avis);
  }
}

class AnnonceController {
  final Annonce annonce;
  late EtatAnnonce etat;

  AnnonceController(this.annonce, this.etat);

  void setEtat(EtatAnnonce etat) {
    this.etat = etat;
  }

  void publier() {
    etat.publier(this.annonce);
  }

  void repondre(String id_u) {
    etat.repondre(this.annonce, id_u);
  }

  void cloturer() {
    etat.cloturer(this.annonce);
  }

  void mettreAvis(String id_u, String avis) {
    etat.mettreAvis(this.annonce, id_u, avis);
  }
}

class EtatAnnonce {
  void publier(Annonce a) async {}

  void repondre(Annonce a, String id_u) async {}

  void cloturer(Annonce a) async {}

  void mettreAvis(Annonce a, String id_u, String avis) async {}
}

class AnnonceNonPublie extends EtatAnnonce {
  @override
  void publier(Annonce a) async {
    await local.AnnonceQueries.updateAnnonceEtat(a.id, 2);
    String newId = await dist.AnnonceQueries.publishAnnonce(a);
    await local.AnnonceQueries.updateAnnonceId(a.id, newId);
    a.controller.setEtat(AnnonceNonRepondu());
  }
}

class AnnonceNonRepondu extends EtatAnnonce {
  @override
  void repondre(Annonce a, String id_u) async {
    await dist.AnnonceQueries.accepterAnnonce(a.id, id_u);
    await local.AnnonceQueries.updateAnnonceEtat(a.id, 3);
    await dist.AnnonceQueries.updateAnnonceEtat(a.id, 3);
    a.controller.setEtat(AnnonceRepondu());
  }
}

class AnnonceRepondu extends EtatAnnonce {
  @override
  void cloturer(Annonce a) async {
    await local.AnnonceQueries.updateAnnonceEtat(a.id, 4);
    await dist.AnnonceQueries.updateAnnonceEtat(a.id, 4);
    a.controller.setEtat(AnnonceCloture());
  }
}

class AnnonceCloture extends EtatAnnonce {
  @override
  void mettreAvis(Annonce a, String id_u, String avis) async {
    await dist.AnnonceQueries.mettreAvis(a.id, id_u, avis);
  }
}
import 'package:flutter/material.dart';
import 'package:supabase/supabase.dart';
import 'package:sae_mobile/models/annonce.dart';
import 'package:sae_mobile/models/queries/distant/annonce.dart' as adq;
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:sae_mobile/views/components/CustomButton.dart';
import 'package:sae_mobile/views/components/CustomTextField.dart';

final SupabaseClient supabaseClient = Supabase.instance.client;

class DetailAnnoncePage extends StatefulWidget {
  final Annonce annonce;

  const DetailAnnoncePage({Key? key, required this.annonce}) : super(key: key);

  @override
  _DetailAnnoncePageState createState() => _DetailAnnoncePageState();
}

class _DetailAnnoncePageState extends State<DetailAnnoncePage> {
  late Future<PostgrestList> futureAvis;
  final TextEditingController avisController = TextEditingController();

  @override
  void initState() {
    super.initState();
    futureAvis = adq.AnnonceQueries.getAnnonceAvis(widget.annonce.id);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.annonce.titre),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(
                'Description:',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              Text(widget.annonce.description),
              SizedBox(height: 10),
              Text(
                'Auteur:',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              Text(widget.annonce.auteur.username),
              SizedBox(height: 10),
              Text(
                'Avis:',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              FutureBuilder<PostgrestList>(
                future: futureAvis,
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return CircularProgressIndicator();
                  } else if (snapshot.hasError) {
                    return Text('Error: ${snapshot.error}');
                  } else {
                    return ListView.builder(
                      shrinkWrap: true,
                      itemCount: snapshot.data!.length,
                      itemBuilder: (context, index) {
                        return ListTile(
                          title: Text(snapshot.data![index]['avis']),
                          subtitle: Text(
                              'Par ${snapshot.data![index]['users']['username']}'),
                        );
                      },
                    );
                  }
                },
              ),
              CustomTextField(
                controller: avisController,
                hintText: 'Avis',
              ),
              CustomButton(
                onPressed: () async {
                  await widget.annonce.mettreAvis(
                      supabaseClient.auth.currentUser!.id, avisController.text);
                  avisController.clear();
                  setState(() {
                    futureAvis =
                        adq.AnnonceQueries.getAnnonceAvis(widget.annonce.id);
                  });
                },
                buttonText: 'cloturer',
              ),
            ],
          ),
        ),
      ),
    );
  }
}