774 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			774 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
package application
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"net/http"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	groupstorage "git.coopgo.io/coopgo-platform/groups-management/storage"
 | 
						|
	mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage"
 | 
						|
	gen "git.coopgo.io/coopgo-platform/solidarity-transport/servers/grpc/proto/gen"
 | 
						|
	"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/identification"
 | 
						|
	"github.com/gorilla/mux"
 | 
						|
	"github.com/rs/zerolog/log"
 | 
						|
)
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportOverviewHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		// Parse form to get both query params and form data
 | 
						|
		r.ParseForm()
 | 
						|
 | 
						|
		// Extract filter parameters using the same field names as the old handler
 | 
						|
		tab := r.FormValue("tab")
 | 
						|
		if tab == "" {
 | 
						|
			tab = "solidarityService"  // Default to showing current bookings
 | 
						|
		}
 | 
						|
 | 
						|
		// Extract archived filter
 | 
						|
		archivedFilter := false
 | 
						|
		if archived := r.URL.Query().Get("archived"); archived == "true" {
 | 
						|
			archivedFilter = true
 | 
						|
		}
 | 
						|
 | 
						|
		// Apply filters conditionally based on tab (matching old handler logic)
 | 
						|
		var status, driverID, startDate, endDate, departureGeo, destinationGeo, passengerAddressGeo, driverAddressGeo string
 | 
						|
		var histStatus, histDriverID, histStartDate, histEndDate, histDepartureGeo, histDestinationGeo, histPassengerAddressGeo string
 | 
						|
 | 
						|
		// Driver address geography filter (applies when on drivers tab)
 | 
						|
		if tab == "drivers" {
 | 
						|
			driverAddressGeo = r.FormValue("driver_address_geo")
 | 
						|
		}
 | 
						|
 | 
						|
		if tab == "solidarityService" {
 | 
						|
			status = r.FormValue("status")
 | 
						|
			driverID = r.FormValue("driver_id")
 | 
						|
			startDate = r.FormValue("date_start")
 | 
						|
			endDate = r.FormValue("date_end")
 | 
						|
			departureGeo = r.FormValue("departure_geo")
 | 
						|
			destinationGeo = r.FormValue("destination_geo")
 | 
						|
			passengerAddressGeo = r.FormValue("passenger_address_geo")
 | 
						|
		}
 | 
						|
 | 
						|
		// History filters (apply when on solidarityHistory tab)
 | 
						|
		if tab == "solidarityHistory" {
 | 
						|
			histStatus = r.FormValue("status")  // Note: history uses same field names as current
 | 
						|
			histDriverID = r.FormValue("driver_id")
 | 
						|
			histStartDate = r.FormValue("date_start")
 | 
						|
			histEndDate = r.FormValue("date_end")
 | 
						|
			histDepartureGeo = r.FormValue("departure_geo")
 | 
						|
			histDestinationGeo = r.FormValue("destination_geo")
 | 
						|
			histPassengerAddressGeo = r.FormValue("passenger_address_geo")
 | 
						|
		}
 | 
						|
 | 
						|
		// Set default history dates if not provided
 | 
						|
		if histStartDate == "" {
 | 
						|
			histStartDate = time.Now().Add(-30 * 24 * time.Hour).Format("2006-01-02")
 | 
						|
		}
 | 
						|
		if histEndDate == "" {
 | 
						|
			histEndDate = time.Now().Add(-24 * time.Hour).Format("2006-01-02")
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse geography parameters (format: "layer:code")
 | 
						|
		departureGeoLayer, departureGeoCode := "", ""
 | 
						|
		if departureGeo != "" {
 | 
						|
			parts := strings.SplitN(departureGeo, ":", 2)
 | 
						|
			if len(parts) == 2 {
 | 
						|
				departureGeoLayer, departureGeoCode = parts[0], parts[1]
 | 
						|
			}
 | 
						|
		}
 | 
						|
		destinationGeoLayer, destinationGeoCode := "", ""
 | 
						|
		if destinationGeo != "" {
 | 
						|
			parts := strings.SplitN(destinationGeo, ":", 2)
 | 
						|
			if len(parts) == 2 {
 | 
						|
				destinationGeoLayer, destinationGeoCode = parts[0], parts[1]
 | 
						|
			}
 | 
						|
		}
 | 
						|
		passengerAddressGeoLayer, passengerAddressGeoCode := "", ""
 | 
						|
		if passengerAddressGeo != "" {
 | 
						|
			parts := strings.SplitN(passengerAddressGeo, ":", 2)
 | 
						|
			if len(parts) == 2 {
 | 
						|
				passengerAddressGeoLayer, passengerAddressGeoCode = parts[0], parts[1]
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		histDepartureGeoLayer, histDepartureGeoCode := "", ""
 | 
						|
		if histDepartureGeo != "" {
 | 
						|
			parts := strings.SplitN(histDepartureGeo, ":", 2)
 | 
						|
			if len(parts) == 2 {
 | 
						|
				histDepartureGeoLayer, histDepartureGeoCode = parts[0], parts[1]
 | 
						|
			}
 | 
						|
		}
 | 
						|
		histDestinationGeoLayer, histDestinationGeoCode := "", ""
 | 
						|
		if histDestinationGeo != "" {
 | 
						|
			parts := strings.SplitN(histDestinationGeo, ":", 2)
 | 
						|
			if len(parts) == 2 {
 | 
						|
				histDestinationGeoLayer, histDestinationGeoCode = parts[0], parts[1]
 | 
						|
			}
 | 
						|
		}
 | 
						|
		histPassengerAddressGeoLayer, histPassengerAddressGeoCode := "", ""
 | 
						|
		if histPassengerAddressGeo != "" {
 | 
						|
			parts := strings.SplitN(histPassengerAddressGeo, ":", 2)
 | 
						|
			if len(parts) == 2 {
 | 
						|
				histPassengerAddressGeoLayer, histPassengerAddressGeoCode = parts[0], parts[1]
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse driver address geography parameter
 | 
						|
		driverAddressGeoLayer, driverAddressGeoCode := "", ""
 | 
						|
		if driverAddressGeo != "" {
 | 
						|
			parts := strings.SplitN(driverAddressGeo, ":", 2)
 | 
						|
			if len(parts) == 2 {
 | 
						|
				driverAddressGeoLayer, driverAddressGeoCode = parts[0], parts[1]
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		result, err := h.applicationHandler.GetSolidarityTransportOverview(r.Context(), status, driverID, startDate, endDate, departureGeoLayer, departureGeoCode, destinationGeoLayer, destinationGeoCode, passengerAddressGeoLayer, passengerAddressGeoCode, histStatus, histDriverID, histStartDate, histEndDate, histDepartureGeoLayer, histDepartureGeoCode, histDestinationGeoLayer, histDestinationGeoCode, histPassengerAddressGeoLayer, histPassengerAddressGeoCode, archivedFilter, driverAddressGeoLayer, driverAddressGeoCode)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving solidarity transport overview")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Build filters map for template (matching old handler format)
 | 
						|
		filters := map[string]any{
 | 
						|
			"tab":                  tab,
 | 
						|
			"date_start":           startDate,
 | 
						|
			"date_end":             endDate,
 | 
						|
			"status":               status,
 | 
						|
			"driver_id":            driverID,
 | 
						|
			"departure_geo":        departureGeo,
 | 
						|
			"destination_geo":      destinationGeo,
 | 
						|
			"passenger_address_geo": passengerAddressGeo,
 | 
						|
			"driver_address_geo":   driverAddressGeo,
 | 
						|
		}
 | 
						|
 | 
						|
		histFilters := map[string]any{
 | 
						|
			"tab":                  tab,
 | 
						|
			"date_start":           histStartDate,
 | 
						|
			"date_end":             histEndDate,
 | 
						|
			"status":               histStatus,
 | 
						|
			"driver_id":            histDriverID,
 | 
						|
			"departure_geo":        histDepartureGeo,
 | 
						|
			"destination_geo":      histDestinationGeo,
 | 
						|
			"passenger_address_geo": histPassengerAddressGeo,
 | 
						|
		}
 | 
						|
 | 
						|
		// Enrich geography filters with names from geography service
 | 
						|
		var enrichedGeoFilters []map[string]string
 | 
						|
		if h.cfg.GetBool("geography.filters.enabled") {
 | 
						|
			geoFilters := h.cfg.Get("geography.filters.geographies")
 | 
						|
			if geoList, ok := geoFilters.([]any); ok {
 | 
						|
				for _, geoItem := range geoList {
 | 
						|
					if geoMap, ok := geoItem.(map[string]any); ok {
 | 
						|
						layer := ""
 | 
						|
						code := ""
 | 
						|
						if l, ok := geoMap["layer"].(string); ok {
 | 
						|
							layer = l
 | 
						|
						}
 | 
						|
						if c, ok := geoMap["code"].(string); ok {
 | 
						|
							code = c
 | 
						|
						}
 | 
						|
 | 
						|
						enrichedGeo := map[string]string{
 | 
						|
							"layer": layer,
 | 
						|
							"code":  code,
 | 
						|
							"name":  code, // Default to code if name fetch fails
 | 
						|
						}
 | 
						|
 | 
						|
						// Fetch name from geography service
 | 
						|
						if layer != "" && code != "" {
 | 
						|
							if geoFeature, err := h.services.Geography.Find(layer, code); err == nil {
 | 
						|
								if name := geoFeature.Properties.MustString("nom"); name != "" {
 | 
						|
									enrichedGeo["name"] = name
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
 | 
						|
						enrichedGeoFilters = append(enrichedGeoFilters, enrichedGeo)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// Sort by name
 | 
						|
			sort.Slice(enrichedGeoFilters, func(i, j int) bool {
 | 
						|
				return enrichedGeoFilters[i]["name"] < enrichedGeoFilters[j]["name"]
 | 
						|
			})
 | 
						|
		}
 | 
						|
 | 
						|
		h.renderer.SolidarityTransportOverview(w, r, result.Accounts, result.AccountsMap, result.BeneficiariesMap, result.Bookings, result.BookingsHistory, filters, histFilters, tab, enrichedGeoFilters, archivedFilter)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportCreateDriverHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if r.Method == "POST" {
 | 
						|
			// Parse form data
 | 
						|
			firstName := r.PostFormValue("first_name")
 | 
						|
			lastName := r.PostFormValue("last_name")
 | 
						|
			email := r.PostFormValue("email")
 | 
						|
			phoneNumber := r.PostFormValue("phone_number")
 | 
						|
			gender := r.PostFormValue("gender")
 | 
						|
 | 
						|
			var birthdate *time.Time
 | 
						|
			if r.PostFormValue("birthdate") != "" {
 | 
						|
				if d, err := time.Parse("2006-01-02", r.PostFormValue("birthdate")); err == nil {
 | 
						|
					birthdate = &d
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// Parse JSON address field
 | 
						|
			var address any
 | 
						|
			if r.PostFormValue("address") != "" {
 | 
						|
				if err := json.Unmarshal([]byte(r.PostFormValue("address")), &address); err != nil {
 | 
						|
					log.Error().Err(err).Msg("failed parsing address JSON")
 | 
						|
					http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// Parse JSON other_properties field
 | 
						|
			var otherProperties any
 | 
						|
			if r.PostFormValue("other_properties") != "" {
 | 
						|
				if err := json.Unmarshal([]byte(r.PostFormValue("other_properties")), &otherProperties); err != nil {
 | 
						|
					log.Error().Err(err).Msg("failed parsing other_properties JSON")
 | 
						|
					http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			driverID, err := h.applicationHandler.CreateSolidarityTransportDriver(
 | 
						|
				r.Context(),
 | 
						|
				firstName,
 | 
						|
				lastName,
 | 
						|
				email,
 | 
						|
				birthdate,
 | 
						|
				phoneNumber,
 | 
						|
				address,
 | 
						|
				gender,
 | 
						|
				otherProperties,
 | 
						|
			)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error creating solidarity transport driver")
 | 
						|
				http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		h.renderer.SolidarityTransportCreateDriver(w, r)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportUpdateDriverHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
 | 
						|
		if r.Method == "POST" {
 | 
						|
			// Parse form data
 | 
						|
			firstName := r.PostFormValue("first_name")
 | 
						|
			lastName := r.PostFormValue("last_name")
 | 
						|
			email := r.PostFormValue("email")
 | 
						|
			phoneNumber := r.PostFormValue("phone_number")
 | 
						|
			gender := r.PostFormValue("gender")
 | 
						|
 | 
						|
			var birthdate *time.Time
 | 
						|
			if r.PostFormValue("birthdate") != "" {
 | 
						|
				if d, err := time.Parse("2006-01-02", r.PostFormValue("birthdate")); err == nil {
 | 
						|
					birthdate = &d
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// Parse JSON address field
 | 
						|
			var address any
 | 
						|
			if r.PostFormValue("address") != "" {
 | 
						|
				if err := json.Unmarshal([]byte(r.PostFormValue("address")), &address); err != nil {
 | 
						|
					log.Error().Err(err).Msg("failed parsing address JSON")
 | 
						|
					http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			// Parse JSON other_properties field
 | 
						|
			var otherProperties any
 | 
						|
			if r.PostFormValue("other_properties") != "" {
 | 
						|
				if err := json.Unmarshal([]byte(r.PostFormValue("other_properties")), &otherProperties); err != nil {
 | 
						|
					log.Error().Err(err).Msg("failed parsing other_properties JSON")
 | 
						|
					http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
					return
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			updatedDriverID, err := h.applicationHandler.UpdateSolidarityTransportDriver(
 | 
						|
				r.Context(),
 | 
						|
				driverID,
 | 
						|
				firstName,
 | 
						|
				lastName,
 | 
						|
				email,
 | 
						|
				birthdate,
 | 
						|
				phoneNumber,
 | 
						|
				address,
 | 
						|
				gender,
 | 
						|
				otherProperties,
 | 
						|
			)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error updating solidarity transport driver")
 | 
						|
				http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", updatedDriverID), http.StatusFound)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		result, err := h.applicationHandler.GetSolidarityTransportDriver(r.Context(), driverID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving solidarity transport driver for update")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		h.renderer.SolidarityTransportUpdateDriver(w, r, result.Driver)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportDriverDisplayHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
 | 
						|
		// Extract tab parameter
 | 
						|
		tab := r.URL.Query().Get("tab")
 | 
						|
		if tab == "" {
 | 
						|
			tab = "documents" // Default tab
 | 
						|
		}
 | 
						|
 | 
						|
		result, err := h.applicationHandler.GetSolidarityTransportDriverData(r.Context(), driverID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving solidarity transport driver data")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		h.renderer.SolidarityTransportDriverDisplay(w, r, result.Driver, result.Availabilities, result.Documents, result.Bookings, result.BeneficiariesMap, result.Stats, result.WalletBalance, tab)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportAddAvailabilityHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if r.Method != "POST" {
 | 
						|
			log.Error().Msg("Wrong method")
 | 
						|
			http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		if err := r.ParseForm(); err != nil {
 | 
						|
			log.Error().Err(err).Msg("error parsing availabilities form")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
 | 
						|
		// Parse form data
 | 
						|
		starttime := r.PostFormValue("starttime")
 | 
						|
		endtime := r.PostFormValue("endtime")
 | 
						|
 | 
						|
		// Parse JSON address field
 | 
						|
		var address any
 | 
						|
		if r.PostFormValue("address") != "" {
 | 
						|
			if err := json.Unmarshal([]byte(r.PostFormValue("address")), &address); err != nil {
 | 
						|
				log.Error().Err(err).Msg("failed parsing address JSON")
 | 
						|
				http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
				return
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse days
 | 
						|
		days := map[string]bool{
 | 
						|
			"monday":    r.PostFormValue("days.monday") == "on",
 | 
						|
			"tuesday":   r.PostFormValue("days.tuesday") == "on",
 | 
						|
			"wednesday": r.PostFormValue("days.wednesday") == "on",
 | 
						|
			"thursday":  r.PostFormValue("days.thursday") == "on",
 | 
						|
			"friday":    r.PostFormValue("days.friday") == "on",
 | 
						|
			"saturday":  r.PostFormValue("days.saturday") == "on",
 | 
						|
			"sunday":    r.PostFormValue("days.sunday") == "on",
 | 
						|
		}
 | 
						|
 | 
						|
		err := h.applicationHandler.AddSolidarityTransportAvailability(r.Context(), driverID, starttime, endtime, address, days)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error adding solidarity transport availability")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportArchiveDriverHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
 | 
						|
		err := h.applicationHandler.ArchiveSolidarityTransportDriver(r.Context(), driverID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error archiving solidarity transport driver")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportUnarchiveDriverHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
 | 
						|
		err := h.applicationHandler.UnarchiveSolidarityTransportDriver(r.Context(), driverID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error unarchiving solidarity transport driver")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportDriverDocumentsHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
 | 
						|
		if err := r.ParseMultipartForm(100 * 1024 * 1024); err != nil { // 100 MB limit
 | 
						|
			log.Error().Err(err).Msg("error parsing multipart form")
 | 
						|
			http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		documentType := r.FormValue("type")
 | 
						|
		documentName := r.FormValue("name")
 | 
						|
 | 
						|
		file, header, err := r.FormFile("file-upload")
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving file")
 | 
						|
			http.Error(w, "Bad Request", http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
		defer file.Close()
 | 
						|
 | 
						|
		if err := h.applicationHandler.AddSolidarityTransportDriverDocument(r.Context(), driverID, file, header.Filename, header.Size, documentType, documentName); err != nil {
 | 
						|
			log.Error().Err(err).Msg("error adding solidarity transport driver document")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportDocumentDownloadHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
		document := vars["document"]
 | 
						|
 | 
						|
		file, info, err := h.applicationHandler.GetSolidarityTransportDriverDocument(r.Context(), driverID, document)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving solidarity transport driver document")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		w.Header().Set("Content-Type", info.ContentType)
 | 
						|
		if _, err = io.Copy(w, file); err != nil {
 | 
						|
			log.Error().Err(err).Msg("error copying file content")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportDeleteAvailabilityHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
		availabilityID := vars["availabilityid"]
 | 
						|
 | 
						|
		err := h.applicationHandler.DeleteSolidarityTransportAvailability(r.Context(), driverID, availabilityID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error deleting solidarity transport availability")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportDriverJourneyHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
		journeyID := vars["journeyid"]
 | 
						|
		passengerID := r.URL.Query().Get("passengerid")
 | 
						|
		replacesBookingID := r.URL.Query().Get("replaces_booking_id")
 | 
						|
 | 
						|
		if r.Method == "POST" {
 | 
						|
			// Parse form data
 | 
						|
			motivation := r.PostFormValue("motivation")
 | 
						|
			message := r.PostFormValue("message")
 | 
						|
			doNotSend := r.PostFormValue("do_not_send") == "on"
 | 
						|
			returnWaitingTimeMinutes := 0
 | 
						|
			if r.PostFormValue("return_waiting_time") != "" {
 | 
						|
				fmt.Sscanf(r.PostFormValue("return_waiting_time"), "%d", &returnWaitingTimeMinutes)
 | 
						|
			}
 | 
						|
 | 
						|
			replacesBookingID := r.PostFormValue("replaces_booking_id")
 | 
						|
			bookingID, err := h.applicationHandler.CreateSolidarityTransportJourneyBooking(r.Context(), driverID, journeyID, passengerID, motivation, message, doNotSend, returnWaitingTimeMinutes, replacesBookingID)
 | 
						|
			if err != nil {
 | 
						|
				log.Error().Err(err).Msg("error creating solidarity transport journey booking")
 | 
						|
				http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			log.Info().Str("booking_id", bookingID).Msg("Solidarity transport booking created successfully")
 | 
						|
			http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/"), http.StatusFound)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Get current user's group
 | 
						|
		g := r.Context().Value(identification.GroupKey)
 | 
						|
		if g == nil {
 | 
						|
			log.Error().Msg("group not found in request context")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
		group := g.(groupstorage.Group)
 | 
						|
 | 
						|
		result, err := h.applicationHandler.GetSolidarityTransportJourneyData(r.Context(), driverID, journeyID, passengerID, group)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving solidarity transport journey data")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		h.renderer.SolidarityTransportDriverJourney(w, r, result.Journey, result.Driver, result.Passenger, result.Beneficiaries, result.PassengerWalletBalance, result.PricingResult, replacesBookingID)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportDriverJourneyToggleNoreturnHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
		journeyID := vars["journeyid"]
 | 
						|
 | 
						|
		err := h.applicationHandler.ToggleSolidarityTransportJourneyNoreturn(r.Context(), driverID, journeyID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error toggling solidarity transport journey noreturn")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s/journeys/%s", driverID, journeyID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportBookingDisplayHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		bookingID := vars["bookingid"]
 | 
						|
 | 
						|
		result, err := h.applicationHandler.GetSolidarityTransportBookingData(r.Context(), bookingID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving solidarity transport booking")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// If booking is cancelled, search for replacement drivers
 | 
						|
		var replacementDrivers any
 | 
						|
		var replacementDriversMap map[string]mobilityaccountsstorage.Account
 | 
						|
		var replacementPricing map[string]map[string]interface{}
 | 
						|
		var replacementLocations map[string]string
 | 
						|
		if result.Booking.Status == "CANCELLED" {
 | 
						|
			// Initialize maps to avoid nil pointer in template
 | 
						|
			replacementDriversMap = make(map[string]mobilityaccountsstorage.Account)
 | 
						|
			replacementPricing = make(map[string]map[string]interface{})
 | 
						|
			replacementLocations = make(map[string]string)
 | 
						|
 | 
						|
			searchResult, err := h.applicationHandler.SearchJourneys(
 | 
						|
				r.Context(),
 | 
						|
				result.Booking.Journey.PassengerPickupDate,
 | 
						|
				result.Booking.Journey.PassengerPickup,
 | 
						|
				result.Booking.Journey.PassengerDrop,
 | 
						|
				result.Booking.PassengerId,
 | 
						|
				result.Booking.DriverId, // Exclude the original driver
 | 
						|
				result.Booking.GroupId,  // Exclude drivers with bookings in this group
 | 
						|
				nil,                     // options - use defaults
 | 
						|
			)
 | 
						|
			if err == nil {
 | 
						|
				replacementDrivers = searchResult.DriverJourneys
 | 
						|
				replacementDriversMap = searchResult.Drivers
 | 
						|
 | 
						|
				// Calculate pricing for each replacement driver journey
 | 
						|
				for _, dj := range searchResult.DriverJourneys {
 | 
						|
					// Extract driver departure location
 | 
						|
					if dj.DriverDeparture != nil && dj.DriverDeparture.Serialized != "" {
 | 
						|
						var feature map[string]interface{}
 | 
						|
						if err := json.Unmarshal([]byte(dj.DriverDeparture.Serialized), &feature); err == nil {
 | 
						|
							if props, ok := feature["properties"].(map[string]interface{}); ok {
 | 
						|
								if name, ok := props["name"].(string); ok {
 | 
						|
									replacementLocations[dj.Id] = name
 | 
						|
								} else if label, ok := props["label"].(string); ok {
 | 
						|
									replacementLocations[dj.Id] = label
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
					pricingResult, err := h.applicationHandler.CalculateSolidarityTransportPricing(r.Context(), dj, result.Booking.PassengerId)
 | 
						|
					if err == nil {
 | 
						|
						pricing := map[string]interface{}{
 | 
						|
							"passenger": map[string]interface{}{
 | 
						|
								"amount": pricingResult["passenger"].Amount,
 | 
						|
								"currency": pricingResult["passenger"].Currency,
 | 
						|
							},
 | 
						|
							"driver": map[string]interface{}{
 | 
						|
								"amount": pricingResult["driver"].Amount,
 | 
						|
								"currency": pricingResult["driver"].Currency,
 | 
						|
							},
 | 
						|
						}
 | 
						|
						replacementPricing[dj.Id] = pricing
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		h.renderer.SolidarityTransportBookingDisplay(w, r, result.Booking, result.Driver, result.Passenger, result.PassengerWalletBalance, replacementDrivers, replacementDriversMap, replacementPricing, replacementLocations)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportCreateReplacementBookingHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		if r.Method != "POST" {
 | 
						|
			http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		oldBookingID := vars["bookingid"]
 | 
						|
 | 
						|
		// Get the old booking to retrieve its data
 | 
						|
		oldBookingResult, err := h.applicationHandler.GetSolidarityTransportBookingData(r.Context(), oldBookingID)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving old booking")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Parse form data for new driver/journey
 | 
						|
		driverID := r.PostFormValue("driver_id")
 | 
						|
		journeyID := r.PostFormValue("journey_id")
 | 
						|
		message := r.PostFormValue("message")
 | 
						|
		doNotSend := r.PostFormValue("do_not_send") == "on"
 | 
						|
 | 
						|
		// Use old booking's data
 | 
						|
		passengerID := oldBookingResult.Booking.PassengerId
 | 
						|
		motivation := ""
 | 
						|
		if oldBookingResult.Booking.Data != nil {
 | 
						|
			if m, ok := oldBookingResult.Booking.Data["motivation"].(string); ok {
 | 
						|
				motivation = m
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// Get the new driver journey to retrieve journey information
 | 
						|
		driverJourneyResp, err := h.services.GRPC.SolidarityTransport.GetDriverJourney(r.Context(), &gen.GetDriverJourneyRequest{
 | 
						|
			DriverId:  driverID,
 | 
						|
			JourneyId: journeyID,
 | 
						|
		})
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error retrieving new driver journey")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		// Calculate return waiting time based on journey type
 | 
						|
		returnWaitingTimeMinutes := 30 // Default for round trips
 | 
						|
		if driverJourneyResp.DriverJourney.Noreturn {
 | 
						|
			returnWaitingTimeMinutes = 0
 | 
						|
		}
 | 
						|
 | 
						|
		// Create the replacement booking with pricing calculated in CreateSolidarityTransportJourneyBooking
 | 
						|
		bookingID, err := h.applicationHandler.CreateSolidarityTransportJourneyBooking(
 | 
						|
			r.Context(),
 | 
						|
			driverID,
 | 
						|
			journeyID,
 | 
						|
			passengerID,
 | 
						|
			motivation,
 | 
						|
			message, // message from form
 | 
						|
			doNotSend, // doNotSend from form checkbox
 | 
						|
			returnWaitingTimeMinutes,
 | 
						|
			oldBookingID,
 | 
						|
		)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error creating replacement booking")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		log.Info().Str("booking_id", bookingID).Str("replaces", oldBookingID).Msg("Replacement booking created successfully")
 | 
						|
 | 
						|
		// Redirect to the new booking
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/bookings/%s", bookingID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportDocumentDeleteHTTPHandler() http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		driverID := vars["driverid"]
 | 
						|
		document := vars["document"]
 | 
						|
 | 
						|
		if err := h.applicationHandler.DeleteSolidarityTransportDriverDocument(r.Context(), driverID, document); err != nil {
 | 
						|
			log.Error().Err(err).Msg("error deleting solidarity transport driver document")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/drivers/%s", driverID), http.StatusFound)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *Handler) SolidarityTransportBookingStatusHTTPHandler(action string) http.HandlerFunc {
 | 
						|
	return func(w http.ResponseWriter, r *http.Request) {
 | 
						|
		vars := mux.Vars(r)
 | 
						|
		bookingID := vars["bookingid"]
 | 
						|
 | 
						|
		// Extract reason from form data for cancellations
 | 
						|
		reason := ""
 | 
						|
		if action == "cancel" && r.Method == "POST" {
 | 
						|
			r.ParseForm()
 | 
						|
			reason = r.PostFormValue("reason")
 | 
						|
		}
 | 
						|
 | 
						|
		err := h.applicationHandler.UpdateSolidarityTransportBookingStatus(r.Context(), bookingID, action, reason, "", false)
 | 
						|
		if err != nil {
 | 
						|
			log.Error().Err(err).Msg("error updating solidarity transport booking status")
 | 
						|
			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		http.Redirect(w, r, fmt.Sprintf("/app/solidarity-transport/bookings/%s", bookingID), http.StatusSeeOther)
 | 
						|
	}
 | 
						|
} |