feat: enrich /api/v1/dashboard with family profile display fields
APIDossierEntry now includes initials, color, age, dob, sex, is_self — computed server-side using the same avatar color palette and age logic as the web portal dashboard. Self entry now includes name (was empty). Relation field now uses proper name from RBAC relation int. Native mobile family switcher UI can display rich profile cards without any additional API calls.
This commit is contained in:
parent
f58a4f804e
commit
13e991aa1c
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"inou/lib"
|
"inou/lib"
|
||||||
)
|
)
|
||||||
|
|
@ -185,6 +186,12 @@ type APIDossierEntry struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Relation string `json:"relation"`
|
Relation string `json:"relation"`
|
||||||
CanAdd bool `json:"can_add"`
|
CanAdd bool `json:"can_add"`
|
||||||
|
Initials string `json:"initials"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
Age string `json:"age"` // e.g. "8y", "42y", "" if unknown
|
||||||
|
DOB string `json:"dob"` // YYYY-MM-DD or ""
|
||||||
|
Sex int `json:"sex"` // 0=unknown, 1=male, 2=female
|
||||||
|
IsSelf bool `json:"is_self"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type APIDashboardResponse struct {
|
type APIDashboardResponse struct {
|
||||||
|
|
@ -206,9 +213,15 @@ func handleAPIDashboard(w http.ResponseWriter, r *http.Request) {
|
||||||
// Add self first
|
// Add self first
|
||||||
dossiers = append(dossiers, APIDossierEntry{
|
dossiers = append(dossiers, APIDossierEntry{
|
||||||
GUID: formatHexID(d.DossierID),
|
GUID: formatHexID(d.DossierID),
|
||||||
Name: "", // Empty means "self"
|
Name: d.Name,
|
||||||
Relation: "self",
|
Relation: "self",
|
||||||
CanAdd: true,
|
CanAdd: true,
|
||||||
|
Initials: apiInitials(d.Name),
|
||||||
|
Color: apiColor(d.DossierID),
|
||||||
|
Age: apiAge(d.DateOfBirth),
|
||||||
|
DOB: apiDOB(d.DateOfBirth),
|
||||||
|
Sex: d.Sex,
|
||||||
|
IsSelf: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add others
|
// Add others
|
||||||
|
|
@ -223,8 +236,13 @@ func handleAPIDashboard(w http.ResponseWriter, r *http.Request) {
|
||||||
dossiers = append(dossiers, APIDossierEntry{
|
dossiers = append(dossiers, APIDossierEntry{
|
||||||
GUID: formatHexID(a.DossierID),
|
GUID: formatHexID(a.DossierID),
|
||||||
Name: target.Name,
|
Name: target.Name,
|
||||||
Relation: "other", // Relation removed from RBAC
|
Relation: relationName(a.Relation),
|
||||||
CanAdd: (a.Ops & lib.PermWrite) != 0,
|
CanAdd: (a.Ops & lib.PermWrite) != 0,
|
||||||
|
Initials: apiInitials(target.Name),
|
||||||
|
Color: apiColor(a.DossierID),
|
||||||
|
Age: apiAge(target.DateOfBirth),
|
||||||
|
DOB: apiDOB(target.DateOfBirth),
|
||||||
|
Sex: target.Sex,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,3 +324,41 @@ func relationName(rel int) string {
|
||||||
default: return "other"
|
default: return "other"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiInitials(name string) string {
|
||||||
|
parts := strings.Fields(name)
|
||||||
|
if len(parts) == 0 { return "?" }
|
||||||
|
first := []rune(parts[0])
|
||||||
|
if len(parts) == 1 {
|
||||||
|
if len(first) == 0 { return "?" }
|
||||||
|
return strings.ToUpper(string(first[:1]))
|
||||||
|
}
|
||||||
|
last := []rune(parts[len(parts)-1])
|
||||||
|
if len(first) == 0 || len(last) == 0 { return "?" }
|
||||||
|
return strings.ToUpper(string(first[:1]) + string(last[:1]))
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiAvatarColors = []string{
|
||||||
|
"#C47A3D", "#5AAD8A", "#7E8FC2", "#C26E6E",
|
||||||
|
"#9A82B8", "#C2963D", "#6BA0B8", "#B87898",
|
||||||
|
"#7DAD6B", "#8B7D6B",
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiColor(id string) string {
|
||||||
|
if len(id) < 2 { return apiAvatarColors[0] }
|
||||||
|
b, _ := strconv.ParseUint(id[len(id)-2:], 16, 8)
|
||||||
|
return apiAvatarColors[b%uint64(len(apiAvatarColors))]
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiAge(dob string) string {
|
||||||
|
if len(dob) < 10 { return "" }
|
||||||
|
t, err := time.Parse("2006-01-02", dob[:10])
|
||||||
|
if err != nil { return "" }
|
||||||
|
years := int(time.Since(t).Hours() / 8766)
|
||||||
|
return fmt.Sprintf("%dy", years)
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiDOB(dob string) string {
|
||||||
|
if len(dob) < 10 { return "" }
|
||||||
|
return dob[:10]
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue