diff --git a/go.mod b/go.mod index 7335778..1f0f378 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,10 @@ replace git.coopgo.io/coopgo-platform/groups-management => ../../coopgo-platform replace git.coopgo.io/coopgo-platform/fleets => ../../coopgo-platform/fleets/ +replace git.coopgo.io/coopgo-platform/agenda => ../../coopgo-platform/agenda/ + require ( + git.coopgo.io/coopgo-platform/agenda v0.0.0-00010101000000-000000000000 git.coopgo.io/coopgo-platform/fleets v0.0.0-00010101000000-000000000000 git.coopgo.io/coopgo-platform/groups-management v0.0.0-00010101000000-000000000000 git.coopgo.io/coopgo-platform/mobility-accounts v0.0.0-00010101000000-000000000000 @@ -71,6 +74,7 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect gopkg.in/ini.v1 v1.66.4 // indirect + gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect gopkg.in/square/go-jose.v2 v2.5.2-0.20210529014059-a5c7eec3c614 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 3671ecc..af717c5 100644 --- a/go.sum +++ b/go.sum @@ -667,6 +667,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/square/go-jose.v2 v2.5.2-0.20210529014059-a5c7eec3c614 h1:lwJmuuJQGclcankpPJwh8rorzB0bNbVALv8phDGh8TQ= gopkg.in/square/go-jose.v2 v2.5.2-0.20210529014059-a5c7eec3c614/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/handlers/application/agenda.go b/handlers/application/agenda.go new file mode 100644 index 0000000..f42fa6f --- /dev/null +++ b/handlers/application/agenda.go @@ -0,0 +1,304 @@ +package application + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "sort" + "strconv" + "time" + + formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/utils/form-validators" + "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" + agenda "git.coopgo.io/coopgo-platform/agenda/grpcapi" + agendastorage "git.coopgo.io/coopgo-platform/agenda/storage" + groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" + "git.coopgo.io/coopgo-platform/groups-management/storage" + mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" + "github.com/gorilla/mux" + "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +type EventsByStartdate []agendastorage.Event + +func (e EventsByStartdate) Len() int { return len(e) } +func (e EventsByStartdate) Less(i, j int) bool { return e[i].Startdate.Before(e[j].Startdate) } +func (e EventsByStartdate) Swap(i, j int) { e[i], e[j] = e[j], e[i] } + +type EventsForm struct { + Name string `json:"name" validate:"required"` + Type string `json:"type" validate:"required"` + Description string `json:"description"` + Address any `json:"address,omitempty"` + Allday bool `json:"allday"` + Startdate *time.Time `json:"startdate"` + Enddate *time.Time `json:"enddate"` + Starttime string `json:"starttime"` + Endtime string `json:"endtime"` + MaxSubscribers int `json:"max_subscribers" validate:"required"` +} + +func (h *ApplicationHandler) AgendaHome(w http.ResponseWriter, r *http.Request) { + resp, err := h.services.GRPC.Agenda.GetEvents(context.TODO(), &agenda.GetEventsRequest{ + Namespaces: []string{"parcoursmob_dispositifs"}, + Mindate: timestamppb.New(time.Now().Add(-24 * time.Hour)), + }) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + responses := []agendastorage.Event{} + + groupids := []string{} + for _, e := range resp.Events { + groupids = append(groupids, e.Owners...) + responses = append(responses, e.ToStorageType()) + // fmt.Println(e) + // fmt.Println(e.ToStorageType()) + } + + sort.Sort(EventsByStartdate(responses)) + + groupsresp, err := h.services.GRPC.GroupsManagement.GetGroupsBatch(context.TODO(), &groupsmanagement.GetGroupsBatchRequest{ + Groupids: groupids, + }) + groups := map[string]any{} + + if err == nil { + for _, g := range groupsresp.Groups { + groups[g.Id] = g.ToStorageType() + } + } + + h.Renderer.AgendaHome(w, r, responses, groups) +} + +func (h *ApplicationHandler) AgendaCreateEvent(w http.ResponseWriter, r *http.Request) { + if r.Method == "POST" { + // Get current group + g := r.Context().Value(identification.GroupKey) + if g == nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + group := g.(storage.Group) + + eventForm, err := parseEventsForm(r) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusBadRequest) + return + } + + fmt.Println(eventForm) + + data, _ := structpb.NewStruct(map[string]any{ + "address": eventForm.Address, + }) + + request := &agenda.CreateEventRequest{ + Event: &agenda.Event{ + Namespace: "parcoursmob_dispositifs", + Owners: []string{group.ID}, + Type: eventForm.Type, + Name: eventForm.Name, + Description: eventForm.Description, + Startdate: timestamppb.New(*eventForm.Startdate), + Enddate: timestamppb.New(*eventForm.Enddate), + Starttime: eventForm.Starttime, + Endtime: eventForm.Endtime, + Allday: eventForm.Allday, + MaxSubscribers: int64(eventForm.MaxSubscribers), + Data: data, + }, + } + + resp, err := h.services.GRPC.Agenda.CreateEvent(context.TODO(), request) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", resp.Event.Id), http.StatusFound) + + } + h.Renderer.AgendaCreateEvent(w, r) +} + +func (h *ApplicationHandler) AgendaDisplayEvent(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + eventid := vars["eventid"] + + request := &agenda.GetEventRequest{ + Id: eventid, + } + + resp, err := h.services.GRPC.Agenda.GetEvent(context.TODO(), request) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + grouprequest := &groupsmanagement.GetGroupRequest{ + Id: resp.Event.Owners[0], + } + + groupresp, err := h.services.GRPC.GroupsManagement.GetGroup(context.TODO(), grouprequest) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + subscribers := map[string]any{} + + subscriberresp, err := h.services.GRPC.MobilityAccounts.GetAccountsBatch( + context.TODO(), + &mobilityaccounts.GetAccountsBatchRequest{ + Accountids: resp.Event.Subscribers, + }, + ) + + if err == nil { + for _, sub := range subscriberresp.Accounts { + subscribers[sub.Id] = sub.ToStorageType() + } + } + + g := r.Context().Value(identification.GroupKey) + if g == nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + group := g.(storage.Group) + + accountids := []string{} + for _, m := range group.Members { + if !contains(resp.Event.Subscribers, m) { + accountids = append(accountids, m) + } + } + + accountresp, err := h.services.GRPC.MobilityAccounts.GetAccountsBatch( + context.TODO(), + &mobilityaccounts.GetAccountsBatchRequest{ + Accountids: accountids, + }, + ) + + accounts := []any{} + + if err == nil { + for _, acc := range accountresp.Accounts { + accounts = append(accounts, acc) + } + } + + h.Renderer.AgendaDisplayEvent(w, r, resp.Event.ToStorageType(), groupresp.Group.ToStorageType(), subscribers, accounts) +} + +func (h *ApplicationHandler) AgendaSubscribeEvent(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + eventid := vars["eventid"] + + if err := r.ParseForm(); err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusBadRequest) + return + } + + subscriber := r.FormValue("subscriber") + + request := &agenda.SubscribeEventRequest{ + Eventid: eventid, + Subscriber: subscriber, + } + + _, err := h.services.GRPC.Agenda.SubscribeEvent(context.TODO(), request) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + http.Redirect(w, r, fmt.Sprintf("/app/agenda/%s", eventid), http.StatusFound) +} + +func parseEventsForm(r *http.Request) (*EventsForm, error) { + if err := r.ParseForm(); err != nil { + return nil, err + } + + var startdate *time.Time + var enddate *time.Time + + if r.PostFormValue("startdate") != "" { + d, err := time.Parse("2006-01-02", r.PostFormValue("startdate")) + if err != nil { + return nil, err + } + startdate = &d + } + + if r.PostFormValue("enddate") != "" { + d, err := time.Parse("2006-01-02", r.PostFormValue("enddate")) + if err != nil { + return nil, err + } + enddate = &d + } + + max_subscribers, err := strconv.Atoi(r.PostFormValue("max_subscribers")) + if err != nil { + return nil, err + } + + formData := &EventsForm{ + Name: r.PostFormValue("name"), + Type: r.PostFormValue("type"), + Description: r.PostFormValue("description"), + Startdate: startdate, + Enddate: enddate, + Starttime: r.PostFormValue("starttime"), + Endtime: r.PostFormValue("endtime"), + MaxSubscribers: max_subscribers, + } + + if r.PostFormValue("allday") == "true" { + formData.Allday = true + } + + if r.PostFormValue("address") != "" { + var a any + json.Unmarshal([]byte(r.PostFormValue("address")), &a) + + formData.Address = a + } + + validate := formvalidators.New() + if err := validate.Struct(formData); err != nil { + return nil, err + } + + return formData, nil +} + +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/handlers/application/beneficiaries.go b/handlers/application/beneficiaries.go index 422a619..a0f9231 100644 --- a/handlers/application/beneficiaries.go +++ b/handlers/application/beneficiaries.go @@ -16,6 +16,7 @@ import ( formvalidators "git.coopgo.io/coopgo-apps/parcoursmob/utils/form-validators" "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" profilepictures "git.coopgo.io/coopgo-apps/parcoursmob/utils/profile-pictures" + fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" "git.coopgo.io/coopgo-platform/groups-management/storage" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" @@ -61,7 +62,7 @@ func (h *ApplicationHandler) BeneficiaryCreate(w http.ResponseWriter, r *http.Re if r.Method == "POST" { - dataMap, err := parseForm(r) + dataMap, err := parseBeneficiariesForm(r) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) @@ -128,7 +129,23 @@ func (h *ApplicationHandler) BeneficiaryDisplay(w http.ResponseWriter, r *http.R //TODO filter namespaces //TODO filter groups - h.Renderer.BeneficiaryDisplay(w, r, resp.Account.ToStorageType()) + bookingsrequest := &fleets.GetDriverBookingsRequest{ + Driver: beneficiaryID, + } + bookingsresp, err := h.services.GRPC.Fleets.GetDriverBookings(context.TODO(), bookingsrequest) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + bookings := []any{} + + for _, b := range bookingsresp.Bookings { + bookings = append(bookings, b.ToStorageType()) + } + + h.Renderer.BeneficiaryDisplay(w, r, resp.Account.ToStorageType(), bookings) } func (h *ApplicationHandler) BeneficiaryUpdate(w http.ResponseWriter, r *http.Request) { @@ -137,7 +154,7 @@ func (h *ApplicationHandler) BeneficiaryUpdate(w http.ResponseWriter, r *http.Re if r.Method == "POST" { - dataMap, err := parseForm(r) + dataMap, err := parseBeneficiariesForm(r) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) @@ -189,56 +206,6 @@ func (h *ApplicationHandler) BeneficiaryUpdate(w http.ResponseWriter, r *http.Re h.Renderer.BeneficiaryUpdate(w, r, resp.Account.ToStorageType()) } -func parseForm(r *http.Request) (map[string]any, error) { - if err := r.ParseForm(); err != nil { - return nil, err - } - - var date *time.Time - - if r.PostFormValue("birthdate") != "" { - d, err := time.Parse("2006-01-02", r.PostFormValue("birthdate")) - if err != nil { - return nil, err - } - date = &d - } - - formData := BeneficiariesForm{ - FirstName: r.PostFormValue("first_name"), - LastName: r.PostFormValue("last_name"), - Email: r.PostFormValue("email"), - Birthdate: date, - PhoneNumber: r.PostFormValue("phone_number"), - Gender: r.PostFormValue("gender"), - } - - if r.PostFormValue("address") != "" { - var a any - json.Unmarshal([]byte(r.PostFormValue("address")), &a) - - formData.Address = a - } - - validate := formvalidators.New() - if err := validate.Struct(formData); err != nil { - return nil, err - } - - d, err := json.Marshal(formData) - if err != nil { - return nil, err - } - - var dataMap map[string]any - err = json.Unmarshal(d, &dataMap) - if err != nil { - return nil, err - } - - return dataMap, nil -} - func (h *ApplicationHandler) BeneficiaryPicture(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) beneficiaryID := vars["beneficiaryid"] @@ -312,3 +279,53 @@ func (h *ApplicationHandler) beneficiaries(r *http.Request) ([]any, error) { return accounts, err } + +func parseBeneficiariesForm(r *http.Request) (map[string]any, error) { + if err := r.ParseForm(); err != nil { + return nil, err + } + + var date *time.Time + + if r.PostFormValue("birthdate") != "" { + d, err := time.Parse("2006-01-02", r.PostFormValue("birthdate")) + if err != nil { + return nil, err + } + date = &d + } + + formData := BeneficiariesForm{ + FirstName: r.PostFormValue("first_name"), + LastName: r.PostFormValue("last_name"), + Email: r.PostFormValue("email"), + Birthdate: date, + PhoneNumber: r.PostFormValue("phone_number"), + Gender: r.PostFormValue("gender"), + } + + if r.PostFormValue("address") != "" { + var a any + json.Unmarshal([]byte(r.PostFormValue("address")), &a) + + formData.Address = a + } + + validate := formvalidators.New() + if err := validate.Struct(formData); err != nil { + return nil, err + } + + d, err := json.Marshal(formData) + if err != nil { + return nil, err + } + + var dataMap map[string]any + err = json.Unmarshal(d, &dataMap) + if err != nil { + return nil, err + } + + return dataMap, nil +} diff --git a/handlers/application/vehicles-management.go b/handlers/application/vehicles-management.go index f5e9e5d..cc504ad 100644 --- a/handlers/application/vehicles-management.go +++ b/handlers/application/vehicles-management.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net/http" + "time" "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" @@ -14,6 +15,7 @@ import ( "github.com/google/uuid" "github.com/gorilla/mux" "google.golang.org/protobuf/types/known/structpb" + "google.golang.org/protobuf/types/known/timestamppb" ) func (h *ApplicationHandler) VehiclesManagementOverview(w http.ResponseWriter, r *http.Request) { @@ -182,6 +184,57 @@ func (h ApplicationHandler) VehicleManagementBookingDisplay(w http.ResponseWrite booking := resp.Booking.ToStorageType() + if r.Method == "POST" { + r.ParseForm() + + newbooking := resp.Booking + + startdate := r.FormValue("startdate") + if startdate != "" { + newstartdate, _ := time.Parse("2006-01-02", startdate) + newbooking.Startdate = timestamppb.New(newstartdate) + + if newstartdate.Before(newbooking.Unavailablefrom.AsTime()) { + newbooking.Unavailablefrom = timestamppb.New(newstartdate) + } + } + + enddate := r.FormValue("enddate") + if enddate != "" { + newenddate, _ := time.Parse("2006-01-02", enddate) + newbooking.Enddate = timestamppb.New(newenddate) + + if newenddate.After(newbooking.Unavailableto.AsTime()) || newenddate.Equal(newbooking.Unavailableto.AsTime()) { + newbooking.Unavailableto = timestamppb.New(newenddate.Add(24 * time.Hour)) + } + } + + unavailablefrom := r.FormValue("unavailablefrom") + if unavailablefrom != "" { + newunavailablefrom, _ := time.Parse("2006-01-02", unavailablefrom) + newbooking.Unavailablefrom = timestamppb.New(newunavailablefrom) + } + + unavailableto := r.FormValue("unavailableto") + if unavailableto != "" { + newunavailableto, _ := time.Parse("2006-01-02", unavailableto) + newbooking.Unavailableto = timestamppb.New(newunavailableto) + } + + request := &fleets.UpdateBookingRequest{ + Booking: newbooking, + } + + _, err := h.services.GRPC.Fleets.UpdateBooking(context.TODO(), request) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + booking = newbooking.ToStorageType() + } + beneficiaryrequest := &mobilityaccounts.GetAccountRequest{ Id: booking.Driver, } diff --git a/handlers/application/vehicles.go b/handlers/application/vehicles.go index 5d26ddc..92f0a3f 100644 --- a/handlers/application/vehicles.go +++ b/handlers/application/vehicles.go @@ -6,10 +6,15 @@ import ( "net/http" "time" + "git.coopgo.io/coopgo-apps/parcoursmob/utils/identification" fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" + groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" + "git.coopgo.io/coopgo-platform/groups-management/storage" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" + "github.com/coreos/go-oidc" "github.com/google/uuid" "github.com/gorilla/mux" + "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -71,6 +76,32 @@ func (h ApplicationHandler) VehiclesSearch(w http.ResponseWriter, r *http.Reques } func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { + // Get Group + g := r.Context().Value(identification.GroupKey) + if g == nil { + fmt.Println("no current group") + w.WriteHeader(http.StatusInternalServerError) + return + } + current_group := g.(storage.Group) + + // Get current user ID + u := r.Context().Value(identification.IdtokenKey) + if u == nil { + fmt.Println("no current user") + w.WriteHeader(http.StatusInternalServerError) + return + } + current_user_token := u.(*oidc.IDToken) + + // Get current user claims + c := r.Context().Value(identification.ClaimsKey) + if c == nil { + fmt.Println("no current user claims") + w.WriteHeader(http.StatusInternalServerError) + return + } + current_user_claims := c.(map[string]any) vars := mux.Vars(r) vehicleid := vars["vehicleid"] @@ -84,6 +115,25 @@ func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { startdate, _ := time.Parse("2006-01-02", start) enddate, _ := time.Parse("2006-01-02", end) + data := map[string]any{ + "booked_by": map[string]any{ + "user": map[string]any{ + "id": current_user_token.Subject, + "display_name": current_user_claims["display_name"], + }, + "group": map[string]any{ + "id": current_group.ID, + "name": current_group.Data["name"], + }, + }, + } + datapb, err := structpb.NewStruct(data) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + booking := &fleets.Booking{ Id: uuid.NewString(), Vehicleid: vehicleid, @@ -92,13 +142,14 @@ func (h ApplicationHandler) Book(w http.ResponseWriter, r *http.Request) { Enddate: timestamppb.New(enddate), Unavailablefrom: timestamppb.New(startdate), Unavailableto: timestamppb.New(enddate.Add(72 * time.Hour)), + Data: datapb, } request := &fleets.CreateBookingRequest{ Booking: booking, } - _, err := h.services.GRPC.Fleets.CreateBooking(context.TODO(), request) + _, err = h.services.GRPC.Fleets.CreateBooking(context.TODO(), request) if err != nil { fmt.Println(err) w.WriteHeader(http.StatusBadRequest) @@ -136,16 +187,34 @@ func (h ApplicationHandler) VehicleBookingDisplay(w http.ResponseWriter, r *http return } - // grouprequest := &groupsmanagement.GetGroupRequest{ - // Id: booking.Vehicle.Administrators[0], - // } + grouprequest := &groupsmanagement.GetGroupRequest{ + Id: booking.Vehicle.Administrators[0], + } - // groupresp, err := h.services.GRPC.GroupsManagement.GetGroup(context.TODO(), grouprequest) - // if err != nil { - // fmt.Println(err) - // w.WriteHeader(http.StatusInternalServerError) - // return - // } + groupresp, err := h.services.GRPC.GroupsManagement.GetGroup(context.TODO(), grouprequest) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } - h.Renderer.VehicleBookingDisplay(w, r, booking, booking.Vehicle, beneficiaryresp.Account.ToStorageType(), "") + h.Renderer.VehicleBookingDisplay(w, r, booking, booking.Vehicle, beneficiaryresp.Account.ToStorageType(), groupresp.Group.ToStorageType()) +} + +func (h ApplicationHandler) VehiclesBookingsList(w http.ResponseWriter, r *http.Request) { + request := &fleets.GetBookingsRequest{} + resp, err := h.services.GRPC.Fleets.GetBookings(context.TODO(), request) + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusNotFound) + return + } + + bookings := []any{} + + for _, b := range resp.Bookings { + bookings = append(bookings, b.ToStorageType()) + } + + h.Renderer.VehicleBookingsList(w, r, bookings) } diff --git a/main.go b/main.go index 859959e..94bba2f 100644 --- a/main.go +++ b/main.go @@ -54,6 +54,7 @@ func main() { r.HandleFunc("/auth/groups/", authHandler.Groups) r.HandleFunc("/auth/groups/switch", authHandler.GroupSwitch) + r.HandleFunc("/", redirectApp) api_router := r.PathPrefix("/api").Subrouter() api_router.HandleFunc("/", apiHandler.NotFound) @@ -68,7 +69,9 @@ func main() { application.HandleFunc("/beneficiaries/{beneficiaryid}", applicationHandler.BeneficiaryDisplay) application.HandleFunc("/beneficiaries/{beneficiaryid}/update", applicationHandler.BeneficiaryUpdate) application.HandleFunc("/beneficiaries/{beneficiaryid}/picture", applicationHandler.BeneficiaryPicture) + application.HandleFunc("/members/{beneficiaryid}/picture", applicationHandler.BeneficiaryPicture) application.HandleFunc("/vehicles/", applicationHandler.VehiclesSearch) + application.HandleFunc("/vehicles/bookings/", applicationHandler.VehiclesBookingsList) application.HandleFunc("/vehicles/bookings/{bookingid}", applicationHandler.VehicleBookingDisplay) application.HandleFunc("/vehicles/v/{vehicleid}/b/{beneficiaryid}", applicationHandler.Book) application.HandleFunc("/vehicles-management/", applicationHandler.VehiclesManagementOverview) @@ -76,6 +79,10 @@ func main() { application.HandleFunc("/vehicles-management/fleet/{vehicleid}", applicationHandler.VehiclesFleetDisplay) application.HandleFunc("/vehicles-management/fleet/{vehicleid}/update", applicationHandler.VehiclesFleetUpdate) application.HandleFunc("/vehicles-management/bookings/{bookingid}", applicationHandler.VehicleManagementBookingDisplay) + application.HandleFunc("/agenda/", applicationHandler.AgendaHome) + application.HandleFunc("/agenda/create-event", applicationHandler.AgendaCreateEvent) + application.HandleFunc("/agenda/{eventid}", applicationHandler.AgendaDisplayEvent) + application.HandleFunc("/agenda/{eventid}/subscribe", applicationHandler.AgendaSubscribeEvent) //TODO Subrouters with middlewares checking security for each module ? application.Use(idp.Middleware) application.Use(idp.GroupsMiddleware) @@ -98,3 +105,7 @@ func main() { log.Fatal(srv.ListenAndServe()) } + +func redirectApp(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, "/app/", http.StatusFound) +} diff --git a/renderer/agenda.go b/renderer/agenda.go new file mode 100644 index 0000000..d96c837 --- /dev/null +++ b/renderer/agenda.go @@ -0,0 +1,40 @@ +package renderer + +import ( + "net/http" + + agendastorage "git.coopgo.io/coopgo-platform/agenda/storage" +) + +const agendaMenu = "events" + +func (renderer *Renderer) AgendaHome(w http.ResponseWriter, r *http.Request, events []agendastorage.Event, groups map[string]any) { + files := renderer.ThemeConfig.GetStringSlice("views.agenda.list.files") + state := NewState(r, renderer.ThemeConfig, agendaMenu) + state.ViewState = map[string]any{ + "events": events, + "groups": groups, + } + + renderer.Render("agenda home", w, r, files, state) +} + +func (renderer *Renderer) AgendaCreateEvent(w http.ResponseWriter, r *http.Request) { + files := renderer.ThemeConfig.GetStringSlice("views.agenda.create_event.files") + state := NewState(r, renderer.ThemeConfig, agendaMenu) + + renderer.Render("agenda create event", w, r, files, state) +} + +func (renderer *Renderer) AgendaDisplayEvent(w http.ResponseWriter, r *http.Request, event any, group any, subscribers map[string]any, beneficiaries any) { + files := renderer.ThemeConfig.GetStringSlice("views.agenda.display_event.files") + state := NewState(r, renderer.ThemeConfig, agendaMenu) + state.ViewState = map[string]any{ + "event": event, + "group": group, + "subscribers": subscribers, + "beneficiaries": beneficiaries, + } + + renderer.Render("agenda create event", w, r, files, state) +} diff --git a/renderer/beneficiaries.go b/renderer/beneficiaries.go index 20d5fe0..614cee8 100644 --- a/renderer/beneficiaries.go +++ b/renderer/beneficiaries.go @@ -50,10 +50,13 @@ type BeneficiariesDisplayState struct { Beneficiary any } -func (renderer *Renderer) BeneficiaryDisplay(w http.ResponseWriter, r *http.Request, beneficiary any) { +func (renderer *Renderer) BeneficiaryDisplay(w http.ResponseWriter, r *http.Request, beneficiary any, bookings []any) { files := renderer.ThemeConfig.GetStringSlice("views.beneficiaries.display.files") state := NewState(r, renderer.ThemeConfig, beneficiariesMenu) - state.ViewState = beneficiary + state.ViewState = map[string]any{ + "beneficiary": beneficiary, + "bookings": bookings, + } renderer.Render("beneficiaries_display", w, r, files, state) } diff --git a/renderer/renderer.go b/renderer/renderer.go index e4f9f66..43900db 100644 --- a/renderer/renderer.go +++ b/renderer/renderer.go @@ -122,6 +122,8 @@ func NewState(r *http.Request, themeConfig *viper.Viper, menuState string) Rende Display: modules["administration"].(bool), Active: menuState == administrationMenu, }, + + //TODO from configuration for icons at least MenuItems: []MenuItem{ { Title: "Tableau de bord", @@ -155,7 +157,7 @@ func NewState(r *http.Request, themeConfig *viper.Viper, menuState string) Rende Title: "Véhicules partagés", Link: "/app/vehicles/", Active: menuState == "vehicles", - Icon: "hero:outline/user-group", + Icon: "tabler-icons:car", }) } @@ -168,11 +170,11 @@ func NewState(r *http.Request, themeConfig *viper.Viper, menuState string) Rende }) } - if modules["events"].(bool) { + if modules["agenda"].(bool) { ls.MenuItems = append(ls.MenuItems, MenuItem{ - Title: "Dispositifs", - Link: "/app/events/", - Active: menuState == "events", + Title: "Agenda dispositifs", + Link: "/app/agenda/", + Active: menuState == "agenda", Icon: "hero:outline/calendar", }) } diff --git a/renderer/vehicles.go b/renderer/vehicles.go index 50982df..0dd88d8 100644 --- a/renderer/vehicles.go +++ b/renderer/vehicles.go @@ -38,3 +38,13 @@ func (renderer *Renderer) VehicleBookingDisplay(w http.ResponseWriter, r *http.R renderer.Render("vehicles search", w, r, files, state) } + +func (renderer *Renderer) VehicleBookingsList(w http.ResponseWriter, r *http.Request, bookings []any) { + files := renderer.ThemeConfig.GetStringSlice("views.vehicles.bookings_list.files") + state := NewState(r, renderer.ThemeConfig, vehiclesMenu) + state.ViewState = map[string]any{ + "bookings": bookings, + } + + renderer.Render("vehicles search", w, r, files, state) +} diff --git a/services/agenda.go b/services/agenda.go new file mode 100644 index 0000000..b27e30f --- /dev/null +++ b/services/agenda.go @@ -0,0 +1,23 @@ +package services + +import ( + agenda "git.coopgo.io/coopgo-platform/agenda/grpcapi" + "google.golang.org/grpc" +) + +type AgendaService struct { + agenda.AgendaClient +} + +func NewAgendaService(dial string) (*AgendaService, error) { + conn, err := grpc.Dial(dial, grpc.WithInsecure()) + + client := agenda.NewAgendaClient(conn) + if err != nil { + return nil, err + } + + return &AgendaService{ + AgendaClient: client, + }, nil +} diff --git a/services/services.go b/services/services.go index bc17da5..14b4890 100644 --- a/services/services.go +++ b/services/services.go @@ -1,6 +1,7 @@ package services import ( + agenda "git.coopgo.io/coopgo-platform/agenda/grpcapi" fleets "git.coopgo.io/coopgo-platform/fleets/grpcapi" groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi" mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" @@ -15,6 +16,7 @@ type GRPCServices struct { MobilityAccounts mobilityaccounts.MobilityAccountsClient GroupsManagement groupsmanagement.GroupsManagementClient Fleets fleets.FleetsClient + Agenda agenda.AgendaClient } func NewServicesHandler(cfg *viper.Viper) (*ServicesHandler, error) { @@ -22,6 +24,7 @@ func NewServicesHandler(cfg *viper.Viper) (*ServicesHandler, error) { mobilityAccountsDial = cfg.GetString("services.grpc.mobilityaccounts.dial") groupsManagementDial = cfg.GetString("services.grpc.groupsmanagement.dial") fleetsDial = cfg.GetString("services.grpc.fleets.dial") + agendaDial = cfg.GetString("services.grpc.agenda.dial") ) mobilityAccounts, err := NewMobilityAccountService(mobilityAccountsDial) if err != nil { @@ -38,11 +41,17 @@ func NewServicesHandler(cfg *viper.Viper) (*ServicesHandler, error) { return nil, err } + agendaSvc, err := NewAgendaService(agendaDial) + if err != nil { + return nil, err + } + return &ServicesHandler{ GRPC: GRPCServices{ MobilityAccounts: mobilityAccounts, GroupsManagement: groupsManagement, Fleets: fleetsSvc, + Agenda: agendaSvc, }, }, nil } diff --git a/themes/default/config.yaml b/themes/default/config.yaml index 13f42f5..5c6fbf0 100644 --- a/themes/default/config.yaml +++ b/themes/default/config.yaml @@ -39,6 +39,10 @@ views: booking_display: files: - layouts/vehicles/booking-display.html + bookings_list: + files: + - layouts/vehicles_management/_partials/bookings-list.html + - layouts/vehicles/bookings-list.html vehicles_management: overview: files: @@ -62,6 +66,17 @@ views: booking_display: files: - layouts/vehicles_management/booking-display.html + agenda: + list: + files: + - layouts/agenda/home.html + display_event: + files: + - layouts/agenda/display-event.html + create_event: + files: + - layouts/_partials/address_autocomplete.html + - layouts/agenda/create-event.html administration: home: files: @@ -96,4 +111,4 @@ icons: hero:solid/search: hero:solid/selector: img:profile-picture-placeholder: - + tabler-icons:car: diff --git a/themes/default/layouts/administration/create_group.html b/themes/default/layouts/administration/create_group.html index eedf35f..c5485ab 100644 --- a/themes/default/layouts/administration/create_group.html +++ b/themes/default/layouts/administration/create_group.html @@ -117,8 +117,8 @@ class="focus:ring-co-blue h-4 w-4 text-co-blue border-gray-300 rounded">
- -

Gestion des dispositifs pour les bénéficiaires (auto-écoles sociales, événements, ...) + +

Agenda des dispositifs pour les bénéficiaires (sessions permis, événements, ...)

diff --git a/themes/default/layouts/administration/display_group.html b/themes/default/layouts/administration/display_group.html index c669351..c321fc6 100644 --- a/themes/default/layouts/administration/display_group.html +++ b/themes/default/layouts/administration/display_group.html @@ -88,8 +88,8 @@ class="focus:ring-co-blue h-4 w-4 text-co-blue border-gray-300 rounded">
- -

Gestion des dispositifs pour les bénéficiaires (auto-écoles sociales, événements, ...) + +

Agenda des dispositifs pour les bénéficiaires (sessions permis, événements, ...)

diff --git a/themes/default/layouts/agenda/create-event.html b/themes/default/layouts/agenda/create-event.html new file mode 100644 index 0000000..115fba6 --- /dev/null +++ b/themes/default/layouts/agenda/create-event.html @@ -0,0 +1,212 @@ +{{ define "content" }} + +
+

Ajouter à l'agenda

+
+ +
+
+
+
+
+

Informations sur le dispositif

+

Informations générales sur le dispositif d'accompagnement à ajouter à l'agenda

+
+
+
+
+ + +
+
+ + +
+
+ +
+ +
+
+ + {{ $fieldName := "address" }} + {{ template "address_autocomplete" dict "FieldName" $fieldName }} +
+
+
+
+ +
+
+
+

Planification

+

Dates et horaires de l'événement

+
+
+
+ +
+ + Toute la journée + + +
+ +
+
+
+ + +
+
+ + +
+ + +
+
+ +
+
+
+ + +
+
+ + +
+ + +
+
+ + +
+ +
+
+
+ +
+
+
+

Paramètres

+

Paramètres du dispositift (nombre de places disponibles, etc...)

+
+
+
+
+ + +
+
+
+
+
+ + + +
+

Certains champs de sont pas valides.

+ + + + +
+
+
+ +{{end}} \ No newline at end of file diff --git a/themes/default/layouts/agenda/display-event.html b/themes/default/layouts/agenda/display-event.html new file mode 100644 index 0000000..fcc31a7 --- /dev/null +++ b/themes/default/layouts/agenda/display-event.html @@ -0,0 +1,140 @@ +{{ define "content" }} +
+
+
+
+

{{.ViewState.event.Name}}

+

+ {{if eq .ViewState.event.Startdate .ViewState.event.Enddate}} + Le {{(timeFrom .ViewState.event.Startdate).Format "02/01/2006"}} + {{else}} + Du {{(timeFrom .ViewState.event.Startdate).Format "02/01/2006"}} au {{(timeFrom .ViewState.event.Enddate).Format "02/01/2006"}} + {{end}} +

+
+
+
+ +
+
+
+
+
+

Informations

+

Informations sur le dispositif.

+
+
+
+ {{if .ViewState.event.Type}} +
+
Type
+
{{.ViewState.event.Type}}
+
+ {{end}} + {{if .ViewState.group}} +
+
Structure gestionnaire
+
{{.ViewState.group.Data.name}}
+
+ {{end}} + {{if .ViewState.event.MaxSubscribers}} +
+
Total places
+
{{.ViewState.event.MaxSubscribers}}
+
+ {{end}} + {{if ne .ViewState.event.MaxSubscribers 0}} +
+
Places restantes
+
{{.ViewState.event.RemainingSubscriptions}}
+
+ {{end}} + {{if .ViewState.event.Data.address}} +
+
Adresse
+
{{.ViewState.event.Data.address.properties.label}}
+
+ {{end}} + {{if .ViewState.event.Description}} +
+
Description
+
{{.ViewState.event.Description}}
+
+ {{end}} +
+
+
+
+
+
+
+

Inscrire un bénéficiaire

+ {{if gt .ViewState.event.RemainingSubscriptions 0}} +
+
+ + + + +
    + + +
+ +
+ +
+ {{else}} +

Il n'y a plus de place disponible

+ {{end}} + {{if .ViewState.subscribers}} +

Inscrits

+
+ {{range .ViewState.subscribers}} + + {{end}} +
+ {{end}} +
+
+
+
+{{ end }} \ No newline at end of file diff --git a/themes/default/layouts/agenda/home.html b/themes/default/layouts/agenda/home.html new file mode 100644 index 0000000..49c9aef --- /dev/null +++ b/themes/default/layouts/agenda/home.html @@ -0,0 +1,110 @@ +{{define "content"}} +
+

Agenda dispositifs

+ +
+
+

+
+ +
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + {{range .ViewState.events}} + + + + + + + + + + + + + {{end}} + + +
+ Type de dispositif + + Structure + + Nom + + Lieu + + Dates + + Places disponibles + + Bénéficiaires positionnés + + Actions +
+
{{.Type}}
+
+ +
+ {{range .Owners}} + {{if (index $.ViewState.groups .)}} + {{(index $.ViewState.groups .).Data.name}} + {{end}} + {{end}} +
+
+
{{.Name}}
+
+
{{if .Data.address}}{{.Data.address.properties.label}}{{end}}
+
+
+ {{if eq .Startdate .Enddate}} + Le {{(timeFrom .Startdate).Format "02/01/2006"}} + {{else}} + Du {{(timeFrom .Startdate).Format "02/01/2006"}}
Au {{(timeFrom .Enddate).Format "02/01/2006"}} + {{end}} +
+
+
{{.RemainingSubscriptions}}
+
+
+ {{range .Subscribers}} + + {{end}} +
+
+ Voir +
+
+
+
+
+
+{{end}} \ No newline at end of file diff --git a/themes/default/layouts/beneficiaries/_partials/beneficiary-vehicles.html b/themes/default/layouts/beneficiaries/_partials/beneficiary-vehicles.html index b5d4a77..897ade0 100644 --- a/themes/default/layouts/beneficiaries/_partials/beneficiary-vehicles.html +++ b/themes/default/layouts/beneficiaries/_partials/beneficiary-vehicles.html @@ -1,8 +1,16 @@ {{define "beneficiary_vehicles"}}
+ {{if .ViewState.bookings}} +

Mises à disposition réalisées

+ + {{end}}

Réserver un véhicule

- +
diff --git a/themes/default/layouts/beneficiaries/display.html b/themes/default/layouts/beneficiaries/display.html index 2f42ebc..4db8599 100644 --- a/themes/default/layouts/beneficiaries/display.html +++ b/themes/default/layouts/beneficiaries/display.html @@ -5,24 +5,24 @@
- +
-

{{.ViewState.Data.first_name}} - {{.ViewState.Data.last_name}}

-

{{if .ViewState.Metadata.created}}Ajouté le par +

{{.ViewState.beneficiary.Data.first_name}} + {{.ViewState.beneficiary.Data.last_name}}

+

{{if .ViewState.beneficiary.Metadata.created}}Ajouté le par Conseiller 1{{end}}

- - --> +
@@ -38,44 +38,44 @@
- {{if .ViewState.Data.email}} + {{if .ViewState.beneficiary.Data.email}}
Email
-
{{.ViewState.Data.email}}
+
{{.ViewState.beneficiary.Data.email}}
{{end}} - {{if .ViewState.Data.phone_number}} + {{if .ViewState.beneficiary.Data.phone_number}}
Téléphone
-
{{.ViewState.Data.phone_number}}
+
{{.ViewState.beneficiary.Data.phone_number}}
{{end}} - {{if .ViewState.Data.birthdate}} + {{if .ViewState.beneficiary.Data.birthdate}}
Date de naissance
-
{{(timeFrom .ViewState.Data.birthdate).Format +
{{(timeFrom .ViewState.beneficiary.Data.birthdate).Format "02/01/2006"}}
{{end}} - {{if and .ViewState.Data.gender (ne .ViewState.Data.gender "0")}} + {{if and .ViewState.beneficiary.Data.gender (ne .ViewState.beneficiary.Data.gender "0")}}
Genre
-
{{genderISO5218 .ViewState.Data.gender}}
+
{{genderISO5218 .ViewState.beneficiary.Data.gender}}
{{end}} - {{if .ViewState.Data.address}} + {{if .ViewState.beneficiary.Data.address}}
Adresse
-
{{.ViewState.Data.address.properties.label}}
+
{{.ViewState.beneficiary.Data.address.properties.label}}
{{end}} - +
Select a tab + + + +
-
Date de fin
-
{{(timeFrom .ViewState.booking.Enddate).Format - "02/01/2006"}}
+
Date de retour
+
+
+
{{(timeFrom .ViewState.booking.Enddate).Format "02/01/2006"}}
+ Modifier +
+
+
+ +
+ +
+
Indisponible à partir du
-
{{(timeFrom .ViewState.booking.Unavailablefrom).Format - "02/01/2006"}}
+
+
+
{{(timeFrom .ViewState.booking.Unavailablefrom).Format "02/01/2006"}}
+ Modifier +
+
+
+ +
+ +
+
Sera à nouveau disponible le
-
{{(timeFrom .ViewState.booking.Unavailableto).Format - "02/01/2006"}}
+
+
+
{{(timeFrom .ViewState.booking.Unavailableto).Format "02/01/2006"}}
+ Modifier +
+
+
+ +
+ +
diff --git a/themes/default/layouts/vehicles_management/fleet-display.html b/themes/default/layouts/vehicles_management/fleet-display.html index 387f392..d786100 100644 --- a/themes/default/layouts/vehicles_management/fleet-display.html +++ b/themes/default/layouts/vehicles_management/fleet-display.html @@ -74,7 +74,7 @@ {{range .ViewState.vehicle.Bookings}}
  • - +

    Du {{(timeFrom .Startdate).Format "02/01/2006"}} au {{(timeFrom .Enddate).Format "02/01/2006"}}

    diff --git a/themes/default/public/css/main.css b/themes/default/public/css/main.css index 5d43147..d445bc0 100644 --- a/themes/default/public/css/main.css +++ b/themes/default/public/css/main.css @@ -798,14 +798,6 @@ html { left: 0px; } -.top-4 { - top: 1rem; -} - -.left-4 { - left: 1rem; -} - .z-40 { z-index: 40; } @@ -830,22 +822,10 @@ html { grid-column: span 3 / span 3; } -.col-span-2 { - grid-column: span 2 / span 2; -} - -.col-span-4 { - grid-column: span 4 / span 4; -} - .col-span-5 { grid-column: span 5 / span 5; } -.m-auto { - margin: auto; -} - .mx-auto { margin-left: auto; margin-right: auto; @@ -861,6 +841,11 @@ html { margin-right: -1rem; } +.my-4 { + margin-top: 1rem; + margin-bottom: 1rem; +} + .-my-1\.5 { margin-top: -0.375rem; margin-bottom: -0.375rem; @@ -871,9 +856,9 @@ html { margin-bottom: -0.25rem; } -.my-4 { - margin-top: 1rem; - margin-bottom: 1rem; +.my-8 { + margin-top: 2rem; + margin-bottom: 2rem; } .-mr-12 { @@ -952,18 +937,18 @@ html { margin-bottom: -1px; } -.-mb-8 { - margin-bottom: -2rem; -} - -.-ml-px { - margin-left: -1px; -} - .-ml-4 { margin-left: -1rem; } +.-mt-4 { + margin-top: -1rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + .-mt-2 { margin-top: -0.5rem; } @@ -980,12 +965,20 @@ html { margin-right: -0.25rem; } -.mb-4 { - margin-bottom: 1rem; +.mr-2 { + margin-right: 0.5rem; } -.-mt-4 { - margin-top: -1rem; +.mr-0 { + margin-right: 0px; +} + +.mt-16 { + margin-top: 4rem; +} + +.mt-12 { + margin-top: 3rem; } .block { @@ -1012,10 +1005,6 @@ html { display: table; } -.flow-root { - display: flow-root; -} - .grid { display: grid; } @@ -1060,10 +1049,6 @@ html { height: 3rem; } -.h-96 { - height: 24rem; -} - .max-h-60 { max-height: 15rem; } @@ -1116,12 +1101,8 @@ html { width: 3rem; } -.w-0\.5 { - width: 0.125rem; -} - -.w-0 { - width: 0px; +.w-11 { + width: 2.75rem; } .min-w-0 { @@ -1190,6 +1171,11 @@ html { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } +.translate-x-5 { + --tw-translate-x: 1.25rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .scale-95 { --tw-scale-x: .95; --tw-scale-y: .95; @@ -1221,10 +1207,6 @@ html { user-select: none; } -.grid-flow-row { - grid-auto-flow: row; -} - .grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } @@ -1233,6 +1215,10 @@ html { grid-template-columns: repeat(1, minmax(0, 1fr)); } +.grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + .grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } @@ -1241,10 +1227,6 @@ html { grid-template-columns: repeat(7, minmax(0, 1fr)); } -.grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); -} - .flex-row { flex-direction: row; } @@ -1344,24 +1326,18 @@ html { margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse))); } -.space-x-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.75rem * var(--tw-space-x-reverse)); - margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); -} - -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1rem * var(--tw-space-x-reverse)); - margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); -} - .-space-x-px > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(-1px * var(--tw-space-x-reverse)); margin-left: calc(-1px * calc(1 - var(--tw-space-x-reverse))); } +.space-x-3 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(0.75rem * var(--tw-space-x-reverse)); + margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); +} + .space-y-8 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse))); @@ -1374,12 +1350,6 @@ html { margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); } -.space-x-6 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(1.5rem * var(--tw-space-x-reverse)); - margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); -} - .space-y-reverse > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 1; } @@ -1478,9 +1448,9 @@ html { border-bottom-right-radius: 0.375rem; } -.rounded-b-2xl { +.rounded-r-2xl { + border-top-right-radius: 1rem; border-bottom-right-radius: 1rem; - border-bottom-left-radius: 1rem; } .rounded-l-2xl { @@ -1488,9 +1458,9 @@ html { border-bottom-left-radius: 1rem; } -.rounded-r-2xl { - border-top-right-radius: 1rem; +.rounded-b-2xl { border-bottom-right-radius: 1rem; + border-bottom-left-radius: 1rem; } .border { @@ -1501,10 +1471,6 @@ html { border-width: 2px; } -.border-4 { - border-width: 4px; -} - .border-r { border-right-width: 1px; } @@ -1521,18 +1487,10 @@ html { border-bottom-width: 2px; } -.border-r-0 { - border-right-width: 0px; -} - .border-l-0 { border-left-width: 0px; } -.border-dashed { - border-style: dashed; -} - .border-gray-200 { --tw-border-opacity: 1; border-color: rgb(229 231 235 / var(--tw-border-opacity)); @@ -1602,31 +1560,6 @@ html { background-color: rgb(249 250 251 / var(--tw-bg-opacity)); } -.bg-gray-200 { - --tw-bg-opacity: 1; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)); -} - -.bg-gray-400 { - --tw-bg-opacity: 1; - background-color: rgb(156 163 175 / var(--tw-bg-opacity)); -} - -.bg-blue-500 { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); -} - -.bg-green-500 { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); -} - -.bg-blue-600 { - --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); -} - .bg-green-100 { --tw-bg-opacity: 1; background-color: rgb(220 252 231 / var(--tw-bg-opacity)); @@ -1637,11 +1570,6 @@ html { background-color: rgb(238 242 255 / var(--tw-bg-opacity)); } -.bg-gray-300 { - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); -} - .bg-indigo-600 { --tw-bg-opacity: 1; background-color: rgb(79 70 229 / var(--tw-bg-opacity)); @@ -1652,6 +1580,11 @@ html { background-color: rgb(17 24 39 / var(--tw-bg-opacity)); } +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + .bg-opacity-75 { --tw-bg-opacity: 0.75; } @@ -1660,8 +1593,8 @@ html { padding: 1rem; } -.p-6 { - padding: 1.5rem; +.p-12 { + padding: 3rem; } .p-2 { @@ -1676,14 +1609,6 @@ html { padding: 0.25rem; } -.p-8 { - padding: 2rem; -} - -.p-12 { - padding: 3rem; -} - .px-4 { padding-left: 1rem; padding-right: 1rem; @@ -1749,26 +1674,16 @@ html { padding-bottom: 0.75rem; } -.px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; -} - -.py-0\.5 { - padding-top: 0.125rem; - padding-bottom: 0.125rem; -} - -.py-0 { - padding-top: 0px; - padding-bottom: 0px; -} - .py-8 { padding-top: 2rem; padding-bottom: 2rem; } +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + .pt-5 { padding-top: 1.25rem; } @@ -1809,40 +1724,28 @@ html { padding-left: 1rem; } -.pb-8 { - padding-bottom: 2rem; -} - -.pt-1\.5 { - padding-top: 0.375rem; -} - -.pt-1 { - padding-top: 0.25rem; -} - .pr-4 { padding-right: 1rem; } -.pr-2 { - padding-right: 0.5rem; +.pr-12 { + padding-right: 3rem; } .pt-8 { padding-top: 2rem; } +.pr-2 { + padding-right: 0.5rem; +} + .pl-1\.5 { padding-left: 0.375rem; } -.pl-3\.5 { - padding-left: 0.875rem; -} - -.pr-12 { - padding-right: 3rem; +.pb-1 { + padding-bottom: 0.25rem; } .text-left { @@ -1857,6 +1760,10 @@ html { text-align: right; } +.text-justify { + text-align: justify; +} + .align-middle { vertical-align: middle; } @@ -1916,10 +1823,6 @@ html { font-weight: 800; } -.font-black { - font-weight: 900; -} - .uppercase { text-transform: uppercase; } @@ -1989,16 +1892,16 @@ html { color: rgb(22 101 52 / var(--tw-text-opacity)); } -.text-gray-600 { - --tw-text-opacity: 1; - color: rgb(75 85 99 / var(--tw-text-opacity)); -} - .text-co-green { --tw-text-opacity: 1; color: rgb(108 193 31 / var(--tw-text-opacity)); } +.text-gray-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + .placeholder-gray-500::-moz-placeholder { --tw-placeholder-opacity: 1; color: rgb(107 114 128 / var(--tw-placeholder-opacity)); @@ -2058,9 +1961,9 @@ html { box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } -.ring-8 { +.ring-0 { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(8px + var(--tw-ring-offset-width)) var(--tw-ring-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color); box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } @@ -2101,6 +2004,14 @@ html { transition-duration: 150ms; } +.transition-colors { + transition-property: color, background-color, border-color, fill, stroke, -webkit-text-decoration-color; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, -webkit-text-decoration-color; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + .duration-300 { transition-duration: 300ms; } @@ -2113,6 +2024,10 @@ html { transition-duration: 75ms; } +.duration-200 { + transition-duration: 200ms; +} + .ease-linear { transition-timing-function: linear; } @@ -2188,21 +2103,16 @@ html { background-color: rgb(36 56 135 / var(--tw-bg-opacity)); } -.hover\:bg-blue-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(29 78 216 / var(--tw-bg-opacity)); -} - -.hover\:bg-indigo-700:hover { - --tw-bg-opacity: 1; - background-color: rgb(67 56 202 / var(--tw-bg-opacity)); -} - .hover\:bg-gray-100:hover { --tw-bg-opacity: 1; background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } +.hover\:bg-blue-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + .hover\:bg-opacity-5:hover { --tw-bg-opacity: 0.05; } @@ -2222,9 +2132,9 @@ html { color: rgb(55 65 81 / var(--tw-text-opacity)); } -.hover\:text-indigo-900:hover { +.hover\:text-co-blue:hover { --tw-text-opacity: 1; - color: rgb(49 46 129 / var(--tw-text-opacity)); + color: rgb(36 56 135 / var(--tw-text-opacity)); } .hover\:text-gray-900:hover { @@ -2232,23 +2142,13 @@ html { color: rgb(17 24 39 / var(--tw-text-opacity)); } -.hover\:text-co-blue:hover { - --tw-text-opacity: 1; - color: rgb(36 56 135 / var(--tw-text-opacity)); -} - -.hover\:text-inherit:hover { - color: inherit; -} - .hover\:text-gray-500:hover { --tw-text-opacity: 1; color: rgb(107 114 128 / var(--tw-text-opacity)); } -.hover\:text-indigo-500:hover { - --tw-text-opacity: 1; - color: rgb(99 102 241 / var(--tw-text-opacity)); +.hover\:text-inherit:hover { + color: inherit; } .focus\:border-transparent:focus { @@ -2327,16 +2227,16 @@ html { --tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity)); } -.focus\:ring-blue-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); -} - .focus\:ring-co-red:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(255 19 0 / var(--tw-ring-opacity)); } +.focus\:ring-blue-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); +} + .focus\:ring-offset-2:focus { --tw-ring-offset-width: 2px; } @@ -2367,6 +2267,10 @@ html { grid-column: span 1 / span 1; } + .sm\:col-span-6 { + grid-column: span 6 / span 6; + } + .sm\:mx-auto { margin-left: auto; margin-right: auto; @@ -2437,10 +2341,6 @@ html { grid-template-columns: repeat(2, minmax(0, 1fr)); } - .sm\:grid-cols-6 { - grid-template-columns: repeat(6, minmax(0, 1fr)); - } - .sm\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } diff --git a/utils/identification/oidc.go b/utils/identification/oidc.go index 7931121..5e60c9a 100644 --- a/utils/identification/oidc.go +++ b/utils/identification/oidc.go @@ -51,7 +51,7 @@ func NewIdentificationProvider(cfg *viper.Viper, services *services.ServicesHand Endpoint: provider.Endpoint(), // "openid" is a required scope for OpenID Connect flows. - Scopes: []string{oidc.ScopeOpenID, "groups", "profile"}, + Scopes: []string{oidc.ScopeOpenID, "groups", "first_name", "last_name", "display_name"}, } var store = sessions.NewCookieStore([]byte(sessionsSecret))