Compare commits

...

4 Commits

Author SHA1 Message Date
4e9fa2337b feat: change color 2025-05-24 17:46:16 +02:00
68899e98bd feat: profile picture support 2025-05-24 17:46:06 +02:00
47f5188961 feat: profile picture 2025-05-24 17:45:47 +02:00
1840194bae feat: use host env var 2025-05-24 17:45:37 +02:00
7 changed files with 42 additions and 22 deletions

View File

@ -37,7 +37,7 @@ func main() {
host := os.Getenv("HOST")
if host == "" {
host = "0.0.0.0"
host = "127.0.0.1"
}
port := os.Getenv("PORT")
@ -45,7 +45,7 @@ func main() {
port = "3000"
}
server := api.NewAPIServer(fmt.Sprintf("127.0.0.1:%s", port), repo, fStorage)
server := api.NewAPIServer(fmt.Sprintf("%s:%s", host, port), repo, fStorage)
if err := server.Run(); err != nil {
log.Fatalln("ERR: Failed to start server:", err)
}

View File

@ -44,13 +44,14 @@ func (h *AuthHandler) getProfile(w http.ResponseWriter, r *http.Request) {
}
if err := json.NewEncoder(w).Encode(map[string]any{
"full_name": user.FullName,
"email": user.Email,
"phoneNumber": user.PhoneNumber,
"isAdmin": user.IsAdmin,
"last_login": user.LastLogin,
"updated_at": user.UpdatedAt,
"created_at": user.CreatedAt,
"full_name": user.FullName,
"email": user.Email,
"phoneNumber": user.PhoneNumber,
"isAdmin": user.IsAdmin,
"last_login": user.LastLogin,
"profile_picture": user.ProfilePicture.String,
"updated_at": user.UpdatedAt,
"created_at": user.CreatedAt,
}); err != nil {
web.Error(w, "failed to encode user profile", http.StatusInternalServerError)
}
@ -124,18 +125,20 @@ func (h *AuthHandler) login(w http.ResponseWriter, r *http.Request) {
AccessToken string `json:"access"`
RefreshToken string `json:"refresh"`
// fields required for UI in account selector, e.g. email, full name and avatar
FullName string `json:"full_name"`
Email string `json:"email"`
Id string `json:"id"`
FullName string `json:"full_name"`
Email string `json:"email"`
Id string `json:"id"`
ProfilePicture string `json:"profile_picture"`
// Avatar
}
if err := encoder.Encode(Response{
AccessToken: accessToken,
RefreshToken: refreshToken,
FullName: user.FullName,
Email: user.Email,
Id: user.ID.String(),
AccessToken: accessToken,
RefreshToken: refreshToken,
FullName: user.FullName,
Email: user.Email,
Id: user.ID.String(),
ProfilePicture: user.ProfilePicture.String,
// Avatar
}); err != nil {
web.Error(w, "failed to encode response", http.StatusInternalServerError)

View File

@ -9,6 +9,7 @@ export interface LoginResponse {
id: string;
email: string;
full_name: string;
profile_picture: string;
access: string;
refresh: string;
}

View File

@ -48,8 +48,18 @@ const AccountList: FC = () => {
className="flex flex-row items-center p-4 border-gray-200 dark:border-gray-700/65 border-b border-r-0 border-l-0 select-none cursor-pointer hover:bg-gray-50/50 dark:hover:bg-gray-800/10 transition-colors mb-0"
>
<div>
<div className="rounded-full p-2 bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-200 mr-3 ring ring-gray-900 dark:ring dark:ring-gray-100">
<User />
<div className="rounded-full w-10 h-10 overflow-hidden bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-200 mr-3 ring ring-gray-400 dark:ring dark:ring-gray-500">
{account.profilePicture ? (
<img
src={account.profilePicture}
className="w-full h-full flex-1"
alt="profile"
/>
) : (
<div className="w-full h-full flex items-center justify-center">
<User />
</div>
)}
</div>
</div>
<div className="flex flex-col">

View File

@ -19,14 +19,14 @@ const AgreementPage: FC = () => {
className="w-16 h-16 mb-4 mt-2 sm:mt-6"
/> */}
<div className="flex flex-row items-center gap-4 mt-2 mb-4 sm:mt-6">
<div className="p-2 bg-gray-100 rounded-full ring ring-gray-900 dark:ring dark:ring-gray-100">
<div className="p-2 bg-gray-100 rounded-full ring ring-gray-400 dark:ring dark:ring-gray-500">
<User size={32} />
</div>
<div className="text-gray-400 dark:text-gray-600">
{/* <Activity /> */}
<ArrowLeftRight />
</div>
<div className="p-2 rounded-full bg-gray-900 ring ring-gray-900 dark:ring dark:ring-gray-100">
<div className="p-2 rounded-full bg-gray-900 ring ring-gray-400 dark:ring dark:ring-gray-500">
{/* <img
src="https://lucide.dev/logo.dark.svg"
className="w-8 h-8"
@ -46,7 +46,7 @@ const AgreementPage: FC = () => {
wants to access your Home Account
</h2>
<div className="flex flex-row items-center justify-center mb-6 gap-2">
<div className="p-2 bg-gray-100 rounded-full ring ring-gray-900 dark:ring dark:ring-gray-100">
<div className="p-2 bg-gray-100 rounded-full ring ring-gray-400 dark:ring dark:ring-gray-500">
<User />
</div>
<p className="text-sm text-gray-500 dark:text-gray-500">

View File

@ -49,6 +49,7 @@ export default function LoginPage() {
accountId: response.id,
label: response.full_name,
email: response.email,
profilePicture: response.profile_picture,
access: response.access,
refresh: response.refresh,
});

View File

@ -6,6 +6,7 @@ export interface RawLocalAccount {
accountId: string;
label: string;
email: string;
profilePicture: string;
access: { data: number[]; iv: number[] };
refresh: { data: number[]; iv: number[] };
updatedAt: string;
@ -15,6 +16,7 @@ export interface LocalAccount {
accountId: string;
label: string;
email: string;
profilePicture: string;
access: string;
refresh: string;
updatedAt: string;
@ -24,6 +26,7 @@ export interface CreateAccountRequest {
accountId: string;
label: string;
email: string;
profilePicture: string;
access: string;
refresh: string;
}
@ -91,6 +94,7 @@ export const useAccountRepo = () => {
accountId: req.accountId,
label: req.label,
email: req.email,
profilePicture: req.profilePicture,
access,
refresh,
updatedAt: new Date().toISOString(),
@ -117,6 +121,7 @@ export const useAccountRepo = () => {
accountId: account.accountId,
label: account.label,
email: account.email,
profilePicture: account.profilePicture,
access: accessToken,
refresh: refreshToken,
updatedAt: account.updatedAt,