Big refactoring of PARCOURSMOB - Initial commit
This commit is contained in:
32
renderer/administration.go
Normal file
32
renderer/administration.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package renderer
|
||||
|
||||
import "net/http"
|
||||
|
||||
const administrationMenu = "administration"
|
||||
|
||||
func (renderer *Renderer) Administration(w http.ResponseWriter, r *http.Request, groups any) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.administration.home.files")
|
||||
state := NewState(r, renderer.ThemeConfig, administrationMenu)
|
||||
state.ViewState = map[string]any{
|
||||
"groups": groups,
|
||||
}
|
||||
|
||||
renderer.Render("administration", w, r, files, state)
|
||||
}
|
||||
|
||||
func (renderer *Renderer) AdministrationCreateGroup(w http.ResponseWriter, r *http.Request) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.administration.create_group.files")
|
||||
state := NewState(r, renderer.ThemeConfig, administrationMenu)
|
||||
|
||||
renderer.Render("administration", w, r, files, state)
|
||||
}
|
||||
|
||||
func (renderer *Renderer) AdministrationGroupDisplay(w http.ResponseWriter, r *http.Request, group any) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.administration.display_group.files")
|
||||
state := NewState(r, renderer.ThemeConfig, administrationMenu)
|
||||
state.ViewState = map[string]any{
|
||||
"group": group,
|
||||
}
|
||||
|
||||
renderer.Render("administration", w, r, files, state)
|
||||
}
|
||||
13
renderer/auth.go
Normal file
13
renderer/auth.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package renderer
|
||||
|
||||
import "net/http"
|
||||
|
||||
func (renderer *Renderer) AuthGroups(w http.ResponseWriter, r *http.Request, groups []any) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.auth.groups.files")
|
||||
state := NewState(r, renderer.ThemeConfig, "")
|
||||
state.ViewState = map[string]any{
|
||||
"groups": groups,
|
||||
}
|
||||
|
||||
renderer.RenderNoLayout("groups switch", w, r, files, state)
|
||||
}
|
||||
67
renderer/beneficiaries.go
Normal file
67
renderer/beneficiaries.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const beneficiariesMenu = "beneficiaries"
|
||||
|
||||
type BeneficiariesListState struct {
|
||||
Count int `json:"count"`
|
||||
CacheId string `json:"cache_id"`
|
||||
Beneficiaries []any `json:"beneficiaries"`
|
||||
}
|
||||
|
||||
func (s BeneficiariesListState) JSON() template.JS {
|
||||
result, _ := json.Marshal(s)
|
||||
return template.JS(result)
|
||||
}
|
||||
|
||||
func (s BeneficiariesListState) JSONWithLimits(a int, b int) template.JS {
|
||||
if b < len(s.Beneficiaries) {
|
||||
s.Beneficiaries = s.Beneficiaries[a:b]
|
||||
}
|
||||
return s.JSON()
|
||||
}
|
||||
|
||||
func (renderer *Renderer) BeneficiariesList(w http.ResponseWriter, r *http.Request, accounts []any, cacheid string) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.list.files")
|
||||
|
||||
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
|
||||
state.ViewState = BeneficiariesListState{
|
||||
Count: len(accounts),
|
||||
CacheId: cacheid,
|
||||
Beneficiaries: accounts,
|
||||
}
|
||||
|
||||
renderer.Render("beneficiaries_list", w, r, files, state)
|
||||
}
|
||||
|
||||
func (renderer *Renderer) BeneficiaryCreate(w http.ResponseWriter, r *http.Request) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.create.files")
|
||||
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
|
||||
|
||||
renderer.Render("beneficiaries_create", w, r, files, state)
|
||||
}
|
||||
|
||||
type BeneficiariesDisplayState struct {
|
||||
Beneficiary any
|
||||
}
|
||||
|
||||
func (renderer *Renderer) BeneficiaryDisplay(w http.ResponseWriter, r *http.Request, beneficiary any) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.display.files")
|
||||
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
|
||||
state.ViewState = beneficiary
|
||||
|
||||
renderer.Render("beneficiaries_display", w, r, files, state)
|
||||
}
|
||||
|
||||
func (renderer *Renderer) BeneficiaryUpdate(w http.ResponseWriter, r *http.Request, beneficiary any) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.update.files")
|
||||
state := NewState(r, renderer.ThemeConfig, beneficiariesMenu)
|
||||
state.ViewState = beneficiary
|
||||
|
||||
renderer.Render("beneficiaries_update", w, r, files, state)
|
||||
}
|
||||
20
renderer/dashboard.go
Normal file
20
renderer/dashboard.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const dashboardMenu = "dashboard"
|
||||
|
||||
func (renderer *Renderer) Dashboard(w http.ResponseWriter, r *http.Request, accounts []any, nbaccounts int) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.dashboard.files")
|
||||
state := NewState(r, renderer.ThemeConfig, dashboardMenu)
|
||||
state.ViewState = map[string]any{
|
||||
"beneficiaries": map[string]any{
|
||||
"count": nbaccounts,
|
||||
"latest": accounts,
|
||||
},
|
||||
}
|
||||
|
||||
renderer.Render("dashboard", w, r, files, state)
|
||||
}
|
||||
77
renderer/func-maps.go
Normal file
77
renderer/func-maps.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TimeFrom(d any) *time.Time {
|
||||
|
||||
if date, ok := d.(time.Time); ok {
|
||||
return &date
|
||||
} else if date, ok := d.(string); ok {
|
||||
datetime, err := time.Parse("2006-01-02T15:04:05Z", date)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &datetime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GenderISO5218(d any) string {
|
||||
if date, ok := d.(string); ok {
|
||||
switch date {
|
||||
case "0":
|
||||
return "Inconnu"
|
||||
case "1":
|
||||
return "Masculin"
|
||||
case "2":
|
||||
return "Féminin"
|
||||
case "9":
|
||||
return "Sans objet"
|
||||
}
|
||||
}
|
||||
if date, ok := d.(int64); ok {
|
||||
switch date {
|
||||
case 0:
|
||||
return "Inconnu"
|
||||
case 1:
|
||||
return "Masculin"
|
||||
case 2:
|
||||
return "Féminin"
|
||||
case 9:
|
||||
return "Sans objet"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func Dict(v ...interface{}) map[string]interface{} {
|
||||
dict := map[string]interface{}{}
|
||||
lenv := len(v)
|
||||
for i := 0; i < lenv; i += 2 {
|
||||
key := strval(v[i])
|
||||
if i+1 >= lenv {
|
||||
dict[key] = ""
|
||||
continue
|
||||
}
|
||||
dict[key] = v[i+1]
|
||||
}
|
||||
return dict
|
||||
}
|
||||
|
||||
func strval(v interface{}) string {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
case error:
|
||||
return v.Error()
|
||||
case fmt.Stringer:
|
||||
return v.String()
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
18
renderer/layout.go
Normal file
18
renderer/layout.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package renderer
|
||||
|
||||
type LayoutState struct {
|
||||
AdministrationState AdministrationState
|
||||
MenuItems []MenuItem
|
||||
}
|
||||
|
||||
type MenuItem struct {
|
||||
Title string
|
||||
Link string
|
||||
Active bool
|
||||
Icon string
|
||||
}
|
||||
|
||||
type AdministrationState struct {
|
||||
Display bool
|
||||
Active bool
|
||||
}
|
||||
184
renderer/renderer.go
Normal file
184
renderer/renderer.go
Normal file
@@ -0,0 +1,184 @@
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/icons"
|
||||
"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
|
||||
"git.coopgo.io/coopgo-platform/groups-management/storage"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Renderer struct {
|
||||
TemplatesDir string
|
||||
GlobalConfig *viper.Viper
|
||||
ThemeConfig *viper.Viper
|
||||
}
|
||||
|
||||
func NewRenderer(global *viper.Viper, templates_dir string) *Renderer {
|
||||
theme := viper.New()
|
||||
theme.SetConfigName("config")
|
||||
theme.AddConfigPath(templates_dir)
|
||||
err := theme.ReadInConfig()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("fatal error config file: %w", err))
|
||||
}
|
||||
return &Renderer{
|
||||
TemplatesDir: templates_dir,
|
||||
GlobalConfig: global,
|
||||
ThemeConfig: theme,
|
||||
}
|
||||
}
|
||||
|
||||
func (renderer *Renderer) Render(name string, w http.ResponseWriter, r *http.Request, files []string, state RenderState) {
|
||||
genericFiles := renderer.ThemeConfig.GetStringSlice("views.generic.files")
|
||||
|
||||
prefixed_files := []string{}
|
||||
for _, f := range genericFiles {
|
||||
prefixed_files = append(prefixed_files, renderer.templateFile(f))
|
||||
}
|
||||
for _, f := range files {
|
||||
prefixed_files = append(prefixed_files, renderer.templateFile(f))
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
t := template.New(name).Funcs(
|
||||
template.FuncMap{
|
||||
"timeFrom": TimeFrom,
|
||||
"genderISO5218": GenderISO5218,
|
||||
"dict": Dict,
|
||||
},
|
||||
)
|
||||
t = template.Must(t.ParseFiles(prefixed_files...))
|
||||
err := t.ExecuteTemplate(w, "main", state)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (renderer *Renderer) RenderNoLayout(name string, w http.ResponseWriter, r *http.Request, files []string, state RenderState) {
|
||||
prefixed_files := []string{}
|
||||
for _, f := range files {
|
||||
prefixed_files = append(prefixed_files, renderer.templateFile(f))
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
t := template.New(name).Funcs(
|
||||
template.FuncMap{
|
||||
"timeFrom": TimeFrom,
|
||||
"genderISO5218": GenderISO5218,
|
||||
"dict": Dict,
|
||||
},
|
||||
)
|
||||
|
||||
t = template.Must(t.ParseFiles(prefixed_files...))
|
||||
err := t.ExecuteTemplate(w, "main", state)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Renderer) templateFile(file string) string {
|
||||
return r.TemplatesDir + file
|
||||
}
|
||||
|
||||
type RenderState struct {
|
||||
icons.IconSet
|
||||
LayoutState
|
||||
Group any
|
||||
Roles any
|
||||
ViewState any // This is a state specific to a given view
|
||||
}
|
||||
|
||||
func NewState(r *http.Request, themeConfig *viper.Viper, menuState string) RenderState {
|
||||
iconset := themeConfig.GetStringMapString("icons.svg")
|
||||
// Get State elements from Request
|
||||
|
||||
g := r.Context().Value(identification.GroupKey)
|
||||
if g == nil {
|
||||
return RenderState{
|
||||
IconSet: icons.NewIconSet(iconset),
|
||||
LayoutState: LayoutState{},
|
||||
}
|
||||
}
|
||||
|
||||
var roles map[string]any
|
||||
|
||||
ro, ok := r.Context().Value(identification.RolesKey).(map[string]any)
|
||||
if ok {
|
||||
roles = ro
|
||||
}
|
||||
|
||||
group := g.(storage.Group)
|
||||
|
||||
modules := group.Data["modules"].(map[string]any)
|
||||
|
||||
ls := LayoutState{
|
||||
AdministrationState: AdministrationState{
|
||||
Display: modules["administration"].(bool),
|
||||
Active: menuState == administrationMenu,
|
||||
},
|
||||
MenuItems: []MenuItem{
|
||||
{
|
||||
Title: "Tableau de bord",
|
||||
Link: "/app/",
|
||||
Active: menuState == "dashboard",
|
||||
Icon: "hero:outline/home",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if modules["beneficiaries"].(bool) {
|
||||
ls.MenuItems = append(ls.MenuItems, MenuItem{
|
||||
Title: "Bénéficiaires",
|
||||
Link: "/app/beneficiaries/",
|
||||
Active: menuState == "beneficiaries",
|
||||
Icon: "hero:outline/user-group",
|
||||
})
|
||||
}
|
||||
|
||||
if modules["journeys"].(bool) {
|
||||
ls.MenuItems = append(ls.MenuItems, MenuItem{
|
||||
Title: "Déplacements",
|
||||
Link: "/app/journeys/",
|
||||
Active: menuState == "journeys",
|
||||
Icon: "hero:outline/user-group",
|
||||
})
|
||||
}
|
||||
|
||||
if modules["vehicles"].(bool) {
|
||||
ls.MenuItems = append(ls.MenuItems, MenuItem{
|
||||
Title: "Véhicules",
|
||||
Link: "/app/vehicles/",
|
||||
Active: menuState == "vehicles",
|
||||
Icon: "hero:outline/user-group",
|
||||
})
|
||||
}
|
||||
|
||||
if modules["vehicles_management"].(bool) {
|
||||
ls.MenuItems = append(ls.MenuItems, MenuItem{
|
||||
Title: "Gestion des véhicules",
|
||||
Link: "/app/vehicles-management/",
|
||||
Active: menuState == "vehicles_management",
|
||||
Icon: "hero:outline/user-group",
|
||||
})
|
||||
}
|
||||
|
||||
if modules["events"].(bool) {
|
||||
ls.MenuItems = append(ls.MenuItems, MenuItem{
|
||||
Title: "Dispositifs",
|
||||
Link: "/app/events/",
|
||||
Active: menuState == "events",
|
||||
Icon: "hero:outline/user-group",
|
||||
})
|
||||
}
|
||||
|
||||
return RenderState{
|
||||
IconSet: icons.NewIconSet(iconset),
|
||||
Group: group,
|
||||
Roles: roles,
|
||||
LayoutState: ls,
|
||||
}
|
||||
}
|
||||
19
renderer/vehicle-management.go
Normal file
19
renderer/vehicle-management.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package renderer
|
||||
|
||||
import "net/http"
|
||||
|
||||
const vehiclesmanagementMenu = "vehicles_management"
|
||||
|
||||
func (renderer *Renderer) VehiclesManagementOverview(w http.ResponseWriter, r *http.Request) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.overview.files")
|
||||
state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu)
|
||||
|
||||
renderer.Render("fleet", w, r, files, state)
|
||||
}
|
||||
|
||||
func (renderer *Renderer) VehiclesFleetAdd(w http.ResponseWriter, r *http.Request) {
|
||||
files := renderer.ThemeConfig.GetStringSlice("views.vehicles_management.fleet_add.files")
|
||||
state := NewState(r, renderer.ThemeConfig, vehiclesmanagementMenu)
|
||||
|
||||
renderer.Render("fleet", w, r, files, state)
|
||||
}
|
||||
Reference in New Issue
Block a user