diff --git a/bin/crm.exe b/bin/crm.exe new file mode 100644 index 0000000..994fd2e Binary files /dev/null and b/bin/crm.exe differ diff --git a/cmd/crm/main.go b/cmd/crm/main.go new file mode 100644 index 0000000..e1ec176 --- /dev/null +++ b/cmd/crm/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "github.com/armanceau/mini-crm/internal/app" + "github.com/armanceau/mini-crm/internal/storage" +) + +func main() { + var store storage.Storer = storage.NewJsonStore("./") + app.Run(store) +} diff --git a/internal/app/app.go b/internal/app/app.go new file mode 100644 index 0000000..831b6dd --- /dev/null +++ b/internal/app/app.go @@ -0,0 +1,143 @@ +package app + +import ( + "bufio" + "flag" + "fmt" + "os" + "strconv" + "strings" + + "github.com/armanceau/mini-crm/internal/storage" +) + +func Run(store storage.Storer) { + nomFlag := flag.String("nom", "", "Nom du contact à ajouter") + emailFlag := flag.String("email", "", "Email du contact à ajouter") + + flag.Parse() + if *nomFlag != "" && *emailFlag != "" { + contact := storage.Contact{ + Nom: strings.TrimSpace(*nomFlag), + Email: strings.TrimSpace(*emailFlag), + } + c := store.Ajouter(contact) + fmt.Println("Contact ajouté via flag :", c.ID, c.Nom, c.Email) + return + } + menu(store) +} + +func menu(store storage.Storer) { + reader := bufio.NewReader(os.Stdin) + + for { + fmt.Println("\n--- cli contact ---") + fmt.Println("1. Ajouter un contact") + fmt.Println("2. Liste des contacts") + fmt.Println("3. Supprimer un contact") + fmt.Println("4. Mettre à jour un contact") + fmt.Println("5. Quitter") + input, _ := reader.ReadString('\n') + choix := strings.TrimSpace(input) + + switch choix { + case "1": + ajouterContact(reader, store) + case "2": + listeContacts(store) + case "3": + supprimerContact(reader, store) + case "4": + mettreAJourContact(reader, store) + case "5": + fmt.Println("À bientôt 👋") + return + default: + fmt.Println("Choix invalide") + } + } + +} + +func New(ID int, Nom string, Email string) storage.Contact { + contact := storage.Contact{ID: ID, Nom: Nom, Email: Email} + return contact +} + +func ajouterContact(reader *bufio.Reader, store storage.Storer) { + fmt.Print("Nom : ") + nom, _ := reader.ReadString('\n') + fmt.Print("Email : ") + email, _ := reader.ReadString('\n') + + contact := storage.Contact{ + Nom: strings.TrimSpace(nom), + Email: strings.TrimSpace(email), + } + + c := store.Ajouter(contact) + fmt.Println("Contact ajouté ✅ :", c.ID, c.Nom, c.Email) +} + +func listeContacts(store storage.Storer) { + contacts := store.Lister() + if len(contacts) == 0 { + fmt.Println("Aucun contact trouvé ❌") + return + } + for _, c := range contacts { + fmt.Printf("[%d] %s - %s\n", c.ID, c.Nom, c.Email) + } +} + +func supprimerContact(reader *bufio.Reader, store storage.Storer) { + fmt.Print("ID du contact à supprimer : ") + input, _ := reader.ReadString('\n') + id, err := strconv.Atoi(strings.TrimSpace(input)) + if err != nil { + fmt.Println("ID invalide") + return + } + if store.Supprimer(id) { + fmt.Println("Contact supprimé ✅") + } else { + fmt.Println("Contact introuvable ❌") + } +} + +func mettreAJourContact(reader *bufio.Reader, store storage.Storer) { + fmt.Print("ID du contact à mettre à jour : ") + input, _ := reader.ReadString('\n') + id, err := strconv.Atoi(strings.TrimSpace(input)) + if err != nil { + fmt.Println("ID invalide") + return + } + + contact, ok := store.Recuperer(id) + if !ok { + fmt.Println("Contact introuvable ❌") + return + } + + fmt.Print("Nouveau nom (laisser vide pour garder actuel) : ") + nom, _ := reader.ReadString('\n') + nom = strings.TrimSpace(nom) + if nom != "" { + contact.Nom = nom + } + + fmt.Print("Nouvel email (laisser vide pour garder actuel) : ") + email, _ := reader.ReadString('\n') + email = strings.TrimSpace(email) + if email != "" { + contact.Email = email + } + + if c, ok := store.MettreAJour(contact); ok { + fmt.Println("Contact mis à jour ✅ :", c.ID, c.Nom, c.Email) + } else { + fmt.Println("Erreur lors de la mise à jour ❌") + } +} diff --git a/internal/storage/memory.go b/internal/storage/memory.go new file mode 100644 index 0000000..69642cb --- /dev/null +++ b/internal/storage/memory.go @@ -0,0 +1,68 @@ +package storage + +import ( + "encoding/json" + "os" +) + +type JsonStore struct { + filePath string + contacts map[int]Contact + nextID int +} + +func NewJsonStore(filePath string) *JsonStore { + return &JsonStore{ + filePath: filePath, + contacts: make(map[int]Contact), + nextID: 1, + } +} + +func (j *JsonStore) save() { + data, _ := json.MarshalIndent(j.contacts, "", " ") + os.WriteFile("contacts.json", data, 0644) +} + +func (j *JsonStore) Ajouter(c Contact) Contact { + c.ID = j.nextID + j.contacts[j.nextID] = c + j.nextID++ + j.save() + return c +} + +func (j *JsonStore) Lister() []Contact { + var list []Contact + for _, c := range j.contacts { + list = append(list, c) + } + return list +} + +func (j *JsonStore) Supprimer(ID int) bool { + if _, ok := j.contacts[ID]; ok { + delete(j.contacts, ID) + j.save() + return true + } + return false +} + +func (j *JsonStore) Recuperer(ID int) (Contact, bool) { + c, ok := j.contacts[ID] + return c, ok +} + +func (j *JsonStore) MettreAJour(c Contact) (Contact, bool) { + if _, ok := j.contacts[c.ID]; ok { + j.contacts[c.ID] = c + j.save() + return c, true + } + return Contact{}, false +} + +func (j *JsonStore) NextID() int { + return j.nextID +} diff --git a/internal/storage/storage.go b/internal/storage/storage.go new file mode 100644 index 0000000..2f78d88 --- /dev/null +++ b/internal/storage/storage.go @@ -0,0 +1,22 @@ +package storage + +import "fmt" + +type Contact struct { + ID int `json:"contact_id"` + Nom string `json:"nom"` + Email string `json:"email"` +} + +type Storer interface { + Ajouter(c Contact) Contact + Lister() []Contact + Supprimer(ID int) bool + MettreAJour(c Contact) (Contact, bool) + Recuperer(ID int) (Contact, bool) + NextID() int +} + +var ErrContactNotFound = func(id int) error { + return fmt.Errorf("Contact avec l'ID non trouvé") +} diff --git a/main.go b/v1/main.go similarity index 100% rename from main.go rename to v1/main.go diff --git a/main_test.go b/v1/main_test.go similarity index 100% rename from main_test.go rename to v1/main_test.go