From 6e040f15cbd0c7875f623622cbf34cb8feae76cc Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:08:49 +0000 Subject: [PATCH 1/4] init: placeholder for React version of SettingsComponent Co-Authored-By: Lukas Burger --- src/app/features/settings/SettingsComponent.tsx | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/app/features/settings/SettingsComponent.tsx diff --git a/src/app/features/settings/SettingsComponent.tsx b/src/app/features/settings/SettingsComponent.tsx new file mode 100644 index 000000000..ee7471933 --- /dev/null +++ b/src/app/features/settings/SettingsComponent.tsx @@ -0,0 +1,3 @@ +export const SettingsComponent = () => { + return null; +}; From 23ecc0600e69f4787973e428c4e1ad3c41686947 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:10:05 +0000 Subject: [PATCH 2/4] feat: port logic from Angular to React - useState for form fields (image, username, bio, email, password), errors, isSubmitting - useEffect for ngOnInit logic (load current user on mount) - onSubmit handler for form submission with error handling - handleLogout handler for logout functionality - Controlled inputs replacing Angular reactive form bindings - JSX template converted from Angular template with existing CSS classes - TODO comments for UserService and Router dependencies Co-Authored-By: Lukas Burger --- .../features/settings/SettingsComponent.tsx | 276 +++++++++++++++++- 1 file changed, 274 insertions(+), 2 deletions(-) diff --git a/src/app/features/settings/SettingsComponent.tsx b/src/app/features/settings/SettingsComponent.tsx index ee7471933..9a35eed54 100644 --- a/src/app/features/settings/SettingsComponent.tsx +++ b/src/app/features/settings/SettingsComponent.tsx @@ -1,3 +1,275 @@ -export const SettingsComponent = () => { - return null; +import { useState, useEffect, FormEvent, ChangeEvent } from "react"; + +/** + * Mirrors the Angular Errors model from core/models/errors.model.ts + */ +interface Errors { + errors: { [key: string]: string }; +} + +/** + * Mirrors the Angular User model from core/auth/user.model.ts + */ +interface User { + email: string; + token: string; + username: string; + bio: string | null; + image: string | null; +} + +/** + * Shape of the settings form state. + * Mirrors the Angular SettingsForm interface (FormControl fields). + */ +interface SettingsFormState { + image: string; + username: string; + bio: string; + email: string; + password: string; +} + +/** + * Props for the ListErrors helper component. + * Replaces Angular's binding. + */ +interface ListErrorsProps { + errors: Errors | null; +} + +/** + * Inline error list component matching the Angular ListErrorsComponent behavior. + * Converts the Errors object into a flat list of "key value" strings. + * + * TODO: Replace with the shared React ListErrors component once it is migrated. + */ +function ListErrors({ errors }: ListErrorsProps) { + if (!errors) { + return null; + } + + const errorList = Object.keys(errors.errors || {}).map( + (key) => `${key} ${errors.errors[key]}`, + ); + + if (errorList.length === 0) { + return null; + } + + return ( +
    + {errorList.map((message) => ( +
  • {message}
  • + ))} +
+ ); +} + +/** + * Dependencies that must be supplied by the consuming application. + * + * In the Angular version these were injected via the constructor (UserService, Router). + * In React they should eventually come from context providers or hooks. + * + * TODO: Replace this props-based dependency injection with React context/hooks + * once UserService and Router are migrated to React equivalents. + */ +interface SettingsComponentDeps { + /** Returns the currently authenticated user, or null. Replaces UserService.getCurrentUserSync(). */ + getCurrentUser: () => User | null; + /** Calls the update API. Replaces UserService.update(). Returns a promise resolving to { user: User }. */ + updateUser: (user: Partial) => Promise<{ user: User }>; + /** Logs the user out. Replaces UserService.logout(). */ + logout: () => void; + /** Navigates to a path. Replaces Router.navigate(). */ + navigateTo: (path: string) => void; +} + +/** + * React version of the Angular SettingsComponent. + * + * Migrated from: + * - src/app/features/settings/settings.component.ts (logic) + * - src/app/features/settings/settings.component.html (template) + * + * The component manages a settings form for the current user's profile, + * including image, username, bio, email, and password fields. + * + * TODO: Wire up real implementations for getCurrentUser, updateUser, logout, and navigateTo + * via React context or a custom hook (e.g. useUserService, useRouter). + */ +export const SettingsComponent = ({ + getCurrentUser, + updateUser, + logout, + navigateTo, +}: SettingsComponentDeps) => { + // --- State (replaces Angular signals and FormGroup) --- + + const [formState, setFormState] = useState({ + image: "", + username: "", + bio: "", + email: "", + password: "", + }); + + const [errors, setErrors] = useState(null); + const [isSubmitting, setIsSubmitting] = useState(false); + + // --- Lifecycle: ngOnInit equivalent --- + // Load the current user on mount and populate the form. + + useEffect(() => { + const user = getCurrentUser(); + if (user) { + setFormState((prev) => ({ + ...prev, + image: user.image ?? "", + username: user.username, + bio: user.bio ?? "", + email: user.email, + // password is intentionally left blank (same as Angular patchValue behavior) + })); + } + }, [getCurrentUser]); + + // --- Handlers --- + + /** + * Generic change handler for all text/email/password inputs and textarea. + * Replaces Angular reactive form's formControlName two-way binding. + */ + const handleChange = ( + e: ChangeEvent, + ) => { + const { name, value } = e.target; + setFormState((prev) => ({ ...prev, [name]: value })); + }; + + /** + * Form submission handler. + * Replaces Angular's (ngSubmit)="submitForm()" and the submitForm() method. + * + * Mirrors the original behavior: + * 1. Set isSubmitting to true + * 2. Call userService.update() with form values + * 3. On success: navigate to the user's profile page + * 4. On error: set errors and reset isSubmitting + */ + const onSubmit = async (e: FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + + try { + const { user } = await updateUser(formState); + // TODO: Replace with React Router navigation (e.g. navigate(`/profile/${user.username}`)) + navigateTo(`/profile/${user.username}`); + } catch (err: unknown) { + setErrors(err as Errors); + setIsSubmitting(false); + } + }; + + /** + * Logout handler. + * Replaces Angular's (click)="logout()" binding. + */ + const handleLogout = () => { + // TODO: Replace with React context-based logout once UserService is migrated + logout(); + }; + + // --- Template (converted from settings.component.html) --- + + return ( +
+
+
+
+

Your Settings

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