mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-26 18:04:45 +10:00
refactor(ui): improve error handling and input safety in app flows
Normalize frontend error rendering and tighten input/path handling across auth, builder, dashboard, and shared components for more resilient UX behavior. Made-with: Cursor
This commit is contained in:
@@ -18,18 +18,49 @@ import type { AuthProvider } from "@/integrations/auth/types";
|
||||
|
||||
import { authClient } from "@/integrations/auth/client";
|
||||
import { orpc } from "@/integrations/orpc/client";
|
||||
import { getReadableErrorMessage } from "@/utils/error-message";
|
||||
|
||||
/**
|
||||
* Get the display name for a social provider
|
||||
*/
|
||||
export function getProviderName(providerId: AuthProvider): string {
|
||||
return match(providerId)
|
||||
.with("credential", () => "Password")
|
||||
.with("passkey", () => "Passkey")
|
||||
.with("google", () => "Google")
|
||||
.with("github", () => "GitHub")
|
||||
.with("linkedin", () => "LinkedIn")
|
||||
.with("custom", () => "Custom OAuth")
|
||||
.with("credential", () =>
|
||||
t({
|
||||
comment: "Authentication provider display name in account settings",
|
||||
message: "Password",
|
||||
}),
|
||||
)
|
||||
.with("passkey", () =>
|
||||
t({
|
||||
comment: "Authentication provider display name in account settings",
|
||||
message: "Passkey",
|
||||
}),
|
||||
)
|
||||
.with("google", () =>
|
||||
t({
|
||||
comment: "Authentication provider display name in account settings",
|
||||
message: "Google",
|
||||
}),
|
||||
)
|
||||
.with("github", () =>
|
||||
t({
|
||||
comment: "Authentication provider display name in account settings",
|
||||
message: "GitHub",
|
||||
}),
|
||||
)
|
||||
.with("linkedin", () =>
|
||||
t({
|
||||
comment: "Authentication provider display name in account settings",
|
||||
message: "LinkedIn",
|
||||
}),
|
||||
)
|
||||
.with("custom", () =>
|
||||
t({
|
||||
comment: "Authentication provider display name in account settings",
|
||||
message: "Custom OAuth",
|
||||
}),
|
||||
)
|
||||
.exhaustive();
|
||||
}
|
||||
|
||||
@@ -85,7 +116,16 @@ export function useAuthProviderActions() {
|
||||
const { error } = await authClient.linkSocial({ provider, callbackURL: "/dashboard/settings/authentication" });
|
||||
|
||||
if (error) {
|
||||
toast.error(error.message, { id: toastId });
|
||||
toast.error(
|
||||
getReadableErrorMessage(
|
||||
error,
|
||||
t({
|
||||
comment: "Fallback toast when linking a social authentication provider fails",
|
||||
message: "Failed to link provider. Please try again.",
|
||||
}),
|
||||
),
|
||||
{ id: toastId },
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -99,7 +139,16 @@ export function useAuthProviderActions() {
|
||||
const { error } = await authClient.unlinkAccount({ providerId: provider, accountId });
|
||||
|
||||
if (error) {
|
||||
toast.error(error.message, { id: toastId });
|
||||
toast.error(
|
||||
getReadableErrorMessage(
|
||||
error,
|
||||
t({
|
||||
comment: "Fallback toast when unlinking a social authentication provider fails",
|
||||
message: "Failed to unlink provider. Please try again.",
|
||||
}),
|
||||
),
|
||||
{ id: toastId },
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { usePrompt } from "@/hooks/use-prompt";
|
||||
import { authClient } from "@/integrations/auth/client";
|
||||
import { getReadableErrorMessage } from "@/utils/error-message";
|
||||
|
||||
export function PasskeysSection() {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -26,7 +27,15 @@ export function PasskeysSection() {
|
||||
},
|
||||
onSuccess: async ({ data, error }) => {
|
||||
if (error) {
|
||||
toast.error(error.message);
|
||||
toast.error(
|
||||
getReadableErrorMessage(
|
||||
error,
|
||||
t({
|
||||
comment: "Fallback toast when passkey registration fails",
|
||||
message: "Failed to register passkey. Please try again.",
|
||||
}),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,7 +45,10 @@ export function PasskeysSection() {
|
||||
const name = await prompt(t`Enter a name for your passkey.`, {
|
||||
description: t`This will help you identify it later, if you plan to have multiple passkeys.`,
|
||||
defaultValue: "",
|
||||
confirmText: t`Save`,
|
||||
confirmText: t({
|
||||
comment: "Passkey rename prompt confirm action in authentication settings",
|
||||
message: "Save",
|
||||
}),
|
||||
});
|
||||
if (name === null) return;
|
||||
|
||||
@@ -46,7 +58,15 @@ export function PasskeysSection() {
|
||||
|
||||
const { error: renameError } = await authClient.passkey.updatePasskey({ id: passkeyId, name: passkeyName });
|
||||
if (renameError) {
|
||||
toast.error(renameError.message);
|
||||
toast.error(
|
||||
getReadableErrorMessage(
|
||||
renameError,
|
||||
t({
|
||||
comment: "Fallback toast when renaming a passkey fails",
|
||||
message: "Failed to rename passkey. Please try again.",
|
||||
}),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,7 +83,15 @@ export function PasskeysSection() {
|
||||
},
|
||||
onSuccess: async ({ error }) => {
|
||||
if (error) {
|
||||
toast.error(error.message);
|
||||
toast.error(
|
||||
getReadableErrorMessage(
|
||||
error,
|
||||
t({
|
||||
comment: "Fallback toast when deleting a passkey fails",
|
||||
message: "Failed to delete passkey. Please try again.",
|
||||
}),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,7 +159,7 @@ export function PasskeysSection() {
|
||||
disabled={deletePasskeyMutation.isPending}
|
||||
>
|
||||
<TrashIcon />
|
||||
<Trans>Delete</Trans>
|
||||
<Trans comment="Passkey row action to remove the selected passkey">Delete</Trans>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,7 +61,9 @@ export function SocialProviderSection({ provider, name, animationDelay = 0 }: So
|
||||
>
|
||||
<Button variant="outline" onClick={handleUnlink}>
|
||||
<LinkBreakIcon />
|
||||
<Trans>Disconnect</Trans>
|
||||
<Trans comment="Authentication settings action to unlink a connected social login provider">
|
||||
Disconnect
|
||||
</Trans>
|
||||
</Button>
|
||||
</motion.div>
|
||||
))
|
||||
@@ -74,7 +76,7 @@ export function SocialProviderSection({ provider, name, animationDelay = 0 }: So
|
||||
>
|
||||
<Button variant="outline" onClick={handleLink}>
|
||||
<LinkIcon />
|
||||
<Trans>Connect</Trans>
|
||||
<Trans comment="Authentication settings action to link a social login provider">Connect</Trans>
|
||||
</Button>
|
||||
</motion.div>
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user