form feedback consolidation
This commit is contained in:
27
src/components/ui/FormFeedback.tsx
Normal file
27
src/components/ui/FormFeedback.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Show, type JSX } from "solid-js";
|
||||||
|
|
||||||
|
export interface FormFeedbackProps {
|
||||||
|
type: "success" | "error";
|
||||||
|
message: string | JSX.Element;
|
||||||
|
show?: boolean;
|
||||||
|
class?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FormFeedback(props: FormFeedbackProps) {
|
||||||
|
const show = () => props.show ?? true;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Show when={show()}>
|
||||||
|
<div
|
||||||
|
class={`text-center text-sm ${
|
||||||
|
props.type === "success" ? "text-green" : "text-red"
|
||||||
|
} ${props.class || ""}`}
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
|
{props.message}
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { FormFeedback };
|
||||||
@@ -15,6 +15,7 @@ import { api } from "~/lib/api";
|
|||||||
import Input from "~/components/ui/Input";
|
import Input from "~/components/ui/Input";
|
||||||
import PasswordInput from "~/components/ui/PasswordInput";
|
import PasswordInput from "~/components/ui/PasswordInput";
|
||||||
import Button from "~/components/ui/Button";
|
import Button from "~/components/ui/Button";
|
||||||
|
import FormFeedback from "~/components/ui/FormFeedback";
|
||||||
|
|
||||||
import type { UserProfile } from "~/types/user";
|
import type { UserProfile } from "~/types/user";
|
||||||
import PasswordStrengthMeter from "~/components/PasswordStrengthMeter";
|
import PasswordStrengthMeter from "~/components/PasswordStrengthMeter";
|
||||||
@@ -611,11 +612,12 @@ export default function AccountPage() {
|
|||||||
: "Set Image"}
|
: "Set Image"}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<Show when={showImageSuccess()}>
|
<FormFeedback
|
||||||
<div class="text-green mt-2 text-center text-sm">
|
type="success"
|
||||||
Profile image updated!
|
message="Profile image updated!"
|
||||||
</div>
|
show={showImageSuccess()}
|
||||||
</Show>
|
class="mt-2"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -694,11 +696,12 @@ export default function AccountPage() {
|
|||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Show when={showEmailSuccess()}>
|
<FormFeedback
|
||||||
<div class="text-green mt-2 text-center text-sm">
|
type="success"
|
||||||
Email updated!
|
message="Email updated!"
|
||||||
</div>
|
show={showEmailSuccess()}
|
||||||
</Show>
|
class="mt-2"
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{/* Display Name Section */}
|
{/* Display Name Section */}
|
||||||
@@ -741,11 +744,12 @@ export default function AccountPage() {
|
|||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Show when={showDisplayNameSuccess()}>
|
<FormFeedback
|
||||||
<div class="text-green mt-2 text-center text-sm">
|
type="success"
|
||||||
Display name updated!
|
message="Display name updated!"
|
||||||
</div>
|
show={showDisplayNameSuccess()}
|
||||||
</Show>
|
class="mt-2"
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -817,9 +821,11 @@ export default function AccountPage() {
|
|||||||
newPasswordConfRef.value.length >= 6
|
newPasswordConfRef.value.length >= 6
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div class="text-red mb-4 text-center text-sm">
|
<FormFeedback
|
||||||
Passwords do not match!
|
type="error"
|
||||||
</div>
|
message="Passwords do not match!"
|
||||||
|
class="mb-4"
|
||||||
|
/>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -831,20 +837,21 @@ export default function AccountPage() {
|
|||||||
Set
|
Set
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Show when={passwordError()}>
|
<FormFeedback
|
||||||
<div class="text-red text-center text-sm">
|
type="error"
|
||||||
{userProfile().hasPassword
|
message={
|
||||||
|
userProfile().hasPassword
|
||||||
? "Password did not match record"
|
? "Password did not match record"
|
||||||
: "Error setting password"}
|
: "Must have email & password provider linked or set password first"
|
||||||
</div>
|
}
|
||||||
</Show>
|
show={passwordError()}
|
||||||
|
/>
|
||||||
|
|
||||||
<Show when={showPasswordSuccess()}>
|
<FormFeedback
|
||||||
<div class="text-green text-center text-sm">
|
type="success"
|
||||||
Password {userProfile().hasPassword ? "changed" : "set"}{" "}
|
message={`Password ${userProfile().hasPassword ? "changed" : "set"} successfully!`}
|
||||||
successfully!
|
show={showPasswordSuccess()}
|
||||||
</div>
|
/>
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -924,11 +931,12 @@ export default function AccountPage() {
|
|||||||
Delete Account
|
Delete Account
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Show when={passwordDeletionError()}>
|
<FormFeedback
|
||||||
<div class="text-red mt-2 text-center text-sm">
|
type="error"
|
||||||
Password did not match record
|
message="Password did not match record"
|
||||||
</div>
|
show={passwordDeletionError()}
|
||||||
</Show>
|
class="mt-2"
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { getClientCookie } from "~/lib/cookies.client";
|
|||||||
import { COUNTDOWN_CONFIG } from "~/config";
|
import { COUNTDOWN_CONFIG } from "~/config";
|
||||||
import Input from "~/components/ui/Input";
|
import Input from "~/components/ui/Input";
|
||||||
import { Button } from "~/components/ui/Button";
|
import { Button } from "~/components/ui/Button";
|
||||||
|
import FormFeedback from "~/components/ui/FormFeedback";
|
||||||
|
|
||||||
export default function RequestPasswordResetPage() {
|
export default function RequestPasswordResetPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -174,42 +175,18 @@ export default function RequestPasswordResetPage() {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div
|
<FormFeedback
|
||||||
class={`${
|
type="success"
|
||||||
showSuccessMessage() ? "" : "opacity-0 select-none"
|
message="If email exists, you will receive an email shortly!"
|
||||||
} text-green flex justify-center italic transition-opacity duration-300 ease-in-out`}
|
show={showSuccessMessage()}
|
||||||
>
|
/>
|
||||||
If email exists, you will receive an email shortly!
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Show when={error()}>
|
<FormFeedback
|
||||||
<div class="mt-4 flex justify-center">
|
type="error"
|
||||||
<div
|
message={error()}
|
||||||
class={`${
|
show={error() !== ""}
|
||||||
error().includes("Too many attempts") ||
|
class="mt-4"
|
||||||
error().includes("wait before requesting")
|
/>
|
||||||
? "border-maroon bg-red rounded-lg border px-4 py-3"
|
|
||||||
: ""
|
|
||||||
} max-w-md text-center`}
|
|
||||||
>
|
|
||||||
<Show when={error().includes("Too many attempts")}>
|
|
||||||
<div class="mb-1 text-base font-semibold">
|
|
||||||
⏱️ Rate Limit Exceeded
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
<div
|
|
||||||
class={`${
|
|
||||||
error().includes("Too many attempts") ||
|
|
||||||
error().includes("wait before requesting")
|
|
||||||
? "text-sm"
|
|
||||||
: "text-red text-sm italic"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{error()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<div class="mt-6 flex justify-center">
|
<div class="mt-6 flex justify-center">
|
||||||
<A
|
<A
|
||||||
|
|||||||
Reference in New Issue
Block a user