From 5bbf80c2ae2105b9e567241dc5afca4733c6f96c Mon Sep 17 00:00:00 2001 From: Knee Cola Date: Mon, 17 Nov 2025 18:58:43 +0100 Subject: [PATCH] Implement redirect with toast notification on profile save MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add gotoHomeWithMessage function to navigationActions - Redirect to home page after successful profile save - Display success message in toast notification instead of in-form - Check for profileSaved URL parameter on home page mount - Clean up URL parameter after showing toast - Move success message translation to home-page section - Remove unused success state and message from AccountForm - Remove useEffect import from AccountForm User experience: After saving profile, users are redirected to the familiar home screen and see a toast notification confirming the save. đŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/lib/actions/navigationActions.ts | 5 +++++ app/lib/actions/userProfileActions.ts | 10 +++++----- app/ui/AccountForm.tsx | 23 ++++------------------- app/ui/MonthLocationList.tsx | 18 ++++++++++++++++-- messages/en.json | 4 ++-- messages/hr.json | 4 ++-- 6 files changed, 34 insertions(+), 30 deletions(-) diff --git a/app/lib/actions/navigationActions.ts b/app/lib/actions/navigationActions.ts index 258a9df..37506c8 100644 --- a/app/lib/actions/navigationActions.ts +++ b/app/lib/actions/navigationActions.ts @@ -9,6 +9,11 @@ export async function gotoHome({year, month}: YearMonth) { await gotoUrl(path); } +export async function gotoHomeWithMessage(locale: string, message: string) { + const path = `/${locale}?${message}=true`; + await gotoUrl(path); +} + export async function gotoUrl(path: string) { console.log(path) revalidatePath(path, "page"); diff --git a/app/lib/actions/userProfileActions.ts b/app/lib/actions/userProfileActions.ts index f870a06..50c21e3 100644 --- a/app/lib/actions/userProfileActions.ts +++ b/app/lib/actions/userProfileActions.ts @@ -7,8 +7,9 @@ import { withUser } from '@/app/lib/auth'; import { AuthenticatedUser } from '../types/next-auth'; import { unstable_noStore as noStore } from 'next/cache'; import { IntlTemplateFn } from '@/app/i18n'; -import { getTranslations } from "next-intl/server"; +import { getTranslations, getLocale } from "next-intl/server"; import { revalidatePath } from 'next/cache'; +import { gotoHomeWithMessage } from './navigationActions'; export type State = { errors?: { @@ -93,8 +94,7 @@ export const updateUserProfile = withUser(async (user: AuthenticatedUser, prevSt revalidatePath('/account'); - return { - message: null, - success: true, - }; + // Get current locale and redirect to home with success message + const locale = await getLocale(); + await gotoHomeWithMessage(locale, 'profileSaved'); }); diff --git a/app/ui/AccountForm.tsx b/app/ui/AccountForm.tsx index cc2aa2a..280226f 100644 --- a/app/ui/AccountForm.tsx +++ b/app/ui/AccountForm.tsx @@ -1,6 +1,6 @@ "use client"; -import { FC, useEffect } from "react"; +import { FC } from "react"; import { UserProfile } from "../lib/db-types"; import { updateUserProfile } from "../lib/actions/userProfileActions"; import { useFormState, useFormStatus } from "react-dom"; @@ -15,11 +15,10 @@ export type AccountFormProps = { type FormFieldsProps = { profile: UserProfile | null; errors: any; - success: boolean; message: string | null; } -const FormFields: FC = ({ profile, errors, success, message }) => { +const FormFields: FC = ({ profile, errors, message }) => { const { pending } = useFormStatus(); const t = useTranslations("account-form"); const locale = useLocale(); @@ -118,16 +117,11 @@ const FormFields: FC = ({ profile, errors, success, message })
- {message && !success && ( + {message && (

{message}

)} - {success && ( -

- {t("success-message")} -

- )}
@@ -147,18 +141,10 @@ const FormFields: FC = ({ profile, errors, success, message }) }; export const AccountForm: FC = ({ profile }) => { - const initialState = { message: null, errors: {}, success: false }; + const initialState = { message: null, errors: {} }; const [state, dispatch] = useFormState(updateUserProfile, initialState); const t = useTranslations("account-form"); - useEffect(() => { - if (state.success) { - // Show success message or toast notification - // For now, we'll just log it - console.log("Profile updated successfully"); - } - }, [state.success]); - return (
@@ -167,7 +153,6 @@ export const AccountForm: FC = ({ profile }) => { diff --git a/app/ui/MonthLocationList.tsx b/app/ui/MonthLocationList.tsx index 879b323..3a2c9cb 100644 --- a/app/ui/MonthLocationList.tsx +++ b/app/ui/MonthLocationList.tsx @@ -9,8 +9,9 @@ import { LocationCard } from "./LocationCard"; import { PrintButton } from "./PrintButton"; import { BillingLocation, YearMonth } from "../lib/db-types"; import { useRouter, useSearchParams } from "next/navigation"; -import { ToastContainer } from 'react-toastify'; +import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; +import { useTranslations } from "next-intl"; const getNextYearMonth = (yearMonth:YearMonth) => { const {year, month} = yearMonth; @@ -38,13 +39,26 @@ export const MonthLocationList:React.FC = ({ const router = useRouter(); const search = useSearchParams(); + const t = useTranslations("home-page"); const initialMonth = search.get('month') - + const [expandedMonth, setExpandedMonth] = React.useState( initialMonth ? parseInt(initialMonth as string) : -1 // no month is expanded ); + // Check for profile saved success message + React.useEffect(() => { + if (search.get('profileSaved') === 'true') { + toast.success(t("profile-saved-message"), { theme: "dark" }); + // Clean up URL parameter + const params = new URLSearchParams(search.toString()); + params.delete('profileSaved'); + const newSearch = params.toString(); + router.replace(newSearch ? `?${newSearch}` : '/'); + } + }, [search, router, t]); + if(!availableYears || !months) { const currentYearMonth:YearMonth = { year: new Date().getFullYear(), diff --git a/messages/en.json b/messages/en.json index 252abe7..9aa61b2 100644 --- a/messages/en.json +++ b/messages/en.json @@ -73,7 +73,8 @@ "table-header-barcode": "2D Barcode", "empty-state-title": "No Barcode Data Found", "empty-state-message": "No bills with 2D barcodes found for {yearMonth}" - } + }, + "profile-saved-message": "Profile updated successfully" }, "bill-delete-form": { "text": "Please confirm deletion of bill \"{bill_name}\" at \"{location_name}\".", @@ -143,7 +144,6 @@ "iban-placeholder": "Enter your IBAN", "save-button": "Save", "cancel-button": "Cancel", - "success-message": "Profile updated successfully", "validation": {} } } \ No newline at end of file diff --git a/messages/hr.json b/messages/hr.json index 1c97911..7ecad93 100644 --- a/messages/hr.json +++ b/messages/hr.json @@ -73,7 +73,8 @@ "table-header-barcode": "2D Barkod", "empty-state-title": "Nema Podataka o Barkodovima", "empty-state-message": "Nema računa s 2D barkodovima za {yearMonth}" - } + }, + "profile-saved-message": "Profil uspjeĆĄno aĆŸuriran" }, "bill-delete-form": { "text": "Molim potvrdi brisanje računa \"{bill_name}\" koji pripada nekretnini \"{location_name}\".", @@ -142,7 +143,6 @@ "iban-placeholder": "Unesite svoj IBAN", "save-button": "Spremi", "cancel-button": "Odbaci", - "success-message": "Profil uspjeĆĄno aĆŸuriran", "validation": {} } } \ No newline at end of file