package handler import ( "log" "net/http" "time" appdb "ntech/internal/db" "ntech/internal/db/sqlite" "ntech/internal/middleware" "ntech/internal/model" ) // Dashboard renderuje početnu stranicu sa pravim podacima iz baze func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // pročitaj i odmah obrišt flash poruku ako postoji var flashGreska string if kol, err := r.Cookie("ntech_flash_greska"); err == nil { flashGreska = kol.Value http.SetCookie(w, &http.Cookie{ Name: "ntech_flash_greska", Value: "", Path: "/", MaxAge: -1, }) } podesavanja, err := sqlite.DohvatiSvaPodesavanja(ctx, h.DB) if err != nil { http.Error(w, "Greška pri učitavanju podešavanja", http.StatusInternalServerError) return } var brojArtikala, aktivniServisi, kriticnaZaliha, aktivniPodsetnici int var prihodOvogMeseca float64 if err := h.DB.QueryRowContext(ctx, "SELECT COUNT(*) FROM artikli", ).Scan(&brojArtikala); err != nil { log.Printf("dashboard: broj artikala: %v", err) } if err := h.DB.QueryRowContext(ctx, ` SELECT COUNT(*) FROM servisni_nalozi WHERE status != 'Završeno'`, ).Scan(&aktivniServisi); err != nil { log.Printf("dashboard: aktivni servisi: %v", err) } // prihod se dohvata samo ako korisnik ima dozvolu dashboard.prihod korisnikDash := middleware.KorisnikIzKonteksta(ctx) if h.DozvoleRepo.ImaDozvolu(ctx, korisnikDash.Uloga, "dashboard.prihod") { if err := h.DB.QueryRowContext(ctx, ` SELECT COALESCE(SUM(ukupno), 0) FROM prodajni_nalozi WHERE substr(datum, 1, 7) = strftime('%Y-%m', 'now', 'localtime')`, ).Scan(&prihodOvogMeseca); err != nil { log.Printf("dashboard: prihod ovog meseca: %v", err) } } if err := h.DB.QueryRowContext(ctx, "SELECT COUNT(*) FROM artikli WHERE kolicina <= kolicina_min", ).Scan(&kriticnaZaliha); err != nil { log.Printf("dashboard: kriticna zaliha: %v", err) } korisnikFilter := appdb.PodsetnikFilter{} if korisnikDash.Uloga == "radnik" { korisnikFilter.KorisnikID = &korisnikDash.ID } if n, err := h.PodsetniciFRepo.BrojAktivnih(ctx, korisnikFilter); err != nil { log.Printf("dashboard: aktivni podsetnici: %v", err) } else { aktivniPodsetnici = n } // poslednjih 5 servisnih naloga sa datumom prijema servisRedovi, err := h.DB.QueryContext(ctx, ` SELECT uredjaj, status, datum_prijema FROM servisni_nalozi ORDER BY datum_prijema DESC LIMIT 5`) if err != nil { log.Printf("dashboard: poslednji servisi: %v", err) } var poslednjiServisi []model.StavkaServisa if servisRedovi != nil { defer servisRedovi.Close() for servisRedovi.Next() { var s model.StavkaServisa var datum time.Time if err := servisRedovi.Scan(&s.Uredjaj, &s.Status, &datum); err == nil { s.BojaTacke = bojaTackeServisa(s.Status) s.DatumPrijema = datum.Format("02.01.") poslednjiServisi = append(poslednjiServisi, s) } } } // artikli sa kritičnom zalihom, sortirani po količini rastuće zaliheRedovi, err := h.DB.QueryContext(ctx, ` SELECT naziv, kolicina FROM artikli WHERE kolicina <= kolicina_min ORDER BY kolicina ASC LIMIT 5`) if err != nil { log.Printf("dashboard: kriticne zalihe: %v", err) } var kriticneZalihe []model.StavkaZalihe if zaliheRedovi != nil { defer zaliheRedovi.Close() for zaliheRedovi.Next() { var z model.StavkaZalihe if err := zaliheRedovi.Scan(&z.Naziv, &z.Kolicina); err == nil { if z.Kolicina == 0 { z.BojaTacke = "#dc2626" } else { z.BojaTacke = "#f97316" } kriticneZalihe = append(kriticneZalihe, z) } } } // poslednjih 5 prodajnih naloga sa nazivom klijenta prodajaRedovi, err := h.DB.QueryContext(ctx, ` SELECT pn.broj_naloga, pn.ukupno, pn.datum, COALESCE(NULLIF(k.naziv_firme, ''), TRIM(COALESCE(k.ime, '') || ' ' || COALESCE(k.prezime, '')), '') AS klijent_naziv FROM prodajni_nalozi pn LEFT JOIN klijenti k ON k.id = pn.klijent_id ORDER BY pn.datum DESC LIMIT 5`) if err != nil { log.Printf("dashboard: poslednje prodaje: %v", err) } var poslednjeProdaje []model.StavkaProdajePregled if prodajaRedovi != nil { defer prodajaRedovi.Close() for prodajaRedovi.Next() { var p model.StavkaProdajePregled var datum time.Time if err := prodajaRedovi.Scan(&p.BrojNaloga, &p.Ukupno, &datum, &p.KlijentNaziv); err == nil { p.Datum = datum.Format("02.01.") poslednjeProdaje = append(poslednjeProdaje, p) } } } ps := h.popuniPodaciStranice(r, podesavanja) ps.Stranica = "dashboard" ps.NaslovStranice = "Dashboard" podaci := model.PodaciDashboarda{ PodaciStranice: ps, BrojArtikala: brojArtikala, AktivniServisi: aktivniServisi, PrihodOvogMeseca: prihodOvogMeseca, KriticnaZaliha: kriticnaZaliha, AktivniPodsetnici: aktivniPodsetnici, PoslednjiServisi: poslednjiServisi, KriticneZalihe: kriticneZalihe, PoslednjeProdaje: poslednjeProdaje, FlashGreska: flashGreska, } h.renderujTemplate(w, "dashboard", podaci) } // bojaTackeServisa vraća hex boju tačke prema statusu naloga func bojaTackeServisa(status string) string { switch status { case "U dijagnostici": return "#3b82f6" case "Čeka delove": return "#f97316" case "U popravci": return "#ca8a04" case "Završeno": return "#16a34a" case "Preuzeto": return "#15803d" default: return "#94a3b8" } }