Skip to content

QF-2017 QDC unified registration cleanup #2408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 33 commits into
base: testing
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4aba5ac
fix unified registration
AhmedCodeGuy May 12, 2025
cac74e0
feat: fix unified registration
AhmedCodeGuy May 13, 2025
9f4b58d
feat: fix unified registration
AhmedCodeGuy May 14, 2025
9ea47cc
fix infinate browser console warnings
AhmedCodeGuy May 15, 2025
f1f7bd9
feat: fix unified registration
AhmedCodeGuy May 17, 2025
9fe4654
feat: fix unified registration
AhmedCodeGuy May 17, 2025
3270dff
remove unused code
AhmedCodeGuy May 18, 2025
491e2a0
feat: fix unified registration
AhmedCodeGuy May 18, 2025
efb364d
feat: fix unified registration
AhmedCodeGuy May 18, 2025
517cc53
feat: fix unified registration
AhmedCodeGuy May 18, 2025
bf137ab
feat: fix unified registration
AhmedCodeGuy May 18, 2025
1fcf3d3
feat: fix unified registration
AhmedCodeGuy May 18, 2025
5a5380d
feat: fix unified registration
AhmedCodeGuy May 18, 2025
cf50c25
feat: fix unified registration
AhmedCodeGuy May 18, 2025
7b3d049
refactor: move navigation constants from constants.ts to navigation.t…
AhmedCodeGuy May 25, 2025
945292c
refactor: replace template literal with classNames utility in Passwor…
AhmedCodeGuy May 25, 2025
cd99745
refactor: consolidate email verification forms and improve auth flow …
AhmedCodeGuy May 25, 2025
b61898a
refactor: consolidate form field generation and adapt for complete si…
AhmedCodeGuy May 25, 2025
7ac172e
refactor: replace back button with Button component and clean up form…
AhmedCodeGuy May 25, 2025
4bc2215
fix: clear general error state before password reset form submission
AhmedCodeGuy May 25, 2025
ad8dce2
refactor: extract privacy policy text into reusable component and rem…
AhmedCodeGuy May 25, 2025
f75d33a
style: convert double quotes to single quotes in server-http.js
AhmedCodeGuy May 25, 2025
563c247
refactor: consolidate navigation constants and improve route document…
AhmedCodeGuy Jun 1, 2025
1c24fc3
refactor: migrate auth forms to use new Input component with AuthForm…
AhmedCodeGuy Jun 1, 2025
6322c85
feat: add noValidate prop to FormBuilder and auth forms to disable br…
AhmedCodeGuy Jun 2, 2025
40a5eec
refactor: replace image components with SVG icons in login screens
AhmedCodeGuy Jun 2, 2025
6961b5d
refactor: rename noValidate prop to shouldSkipValidation in form comp…
AhmedCodeGuy Jun 2, 2025
5982f3b
Merge branch 'testing' into QF-2017-QDC-unified-registration-cleanup
osamasayed Jun 3, 2025
7efbc7d
Merge branch 'testing' of https://github.com/quran/quran.com-frontend…
AhmedCodeGuy Jun 11, 2025
3c4a54b
Merge branch QF-2017-QDC-unified-registration-cleanup of https://gith…
AhmedCodeGuy Jun 11, 2025
e6305e4
refactor: use email regex constant
AhmedCodeGuy Jun 11, 2025
3a8825e
fix: wrap profile completion check in useEffect to prevent render loop
AhmedCodeGuy Jun 11, 2025
e0eaedf
refactor: reorder CSS imports to fix style precedence
AhmedCodeGuy Jun 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .windsurf/rules/prompts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
trigger: always_on
description: For all prompts
---

For all prompts I write do not make any changes, until you have 95% confidence that you know what to build ask me follow up questions until you have that confidence.
3 changes: 2 additions & 1 deletion locales/ar/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -465,5 +465,6 @@
"title": "نطق الكلمة عند النقر عليها"
},
"word-tooltip": "الأداة الإرشادية للكلمات",
"yes": "نعم"
"yes": "نعم",
"back": "عودة"
}
10 changes: 8 additions & 2 deletions locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,12 @@
"sub-header": "Share your interest by filling out this form, and we’ll reach out when a suitable opportunity is available, insha’Allah.",
"title": "Community"
},
"complete-sign-up": "Complete your registration",
"complete-signup": {
"title": "Complete your registration",
"description": "We require the following missing information to complete your registration.",
"verification-code": "Verification Code",
"verification-code-sent-to": "Verification code sent to {{email}}"
},
"consents": {
"communication": {
"body": "🚀 Supercharge your progress through <boldSpan>personalized</boldSpan> notifications about your goal progress, maintaining streaks, and enhancing your usage of our current features.<br></br><br></br> Can we keep you in the loop through email and other channels? You're in control – feel free to adjust these preferences anytime in your account settings.<br></br><br></br> Simply select 'Allow' for <boldSpan>inspiring reminders</boldSpan> or 'Not Now' to decline.",
Expand Down Expand Up @@ -465,5 +470,6 @@
"title": "Word Click"
},
"word-tooltip": "Word Tooltip",
"yes": "Yes"
"yes": "Yes",
"back": "Back"
}
2 changes: 1 addition & 1 deletion locales/en/login.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"first-name-placeholder": "First Name",
"forgot-password": "Forgot password",
"forgot-password-description": "Enter your email address and we'll send you instructions to reset your password.",
"forgot-password-success": "Password reset email sent! Please check your inbox.",
"forgot-password-success": "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes.",
"forgot-password-title": "Forgot password?",
"last-name-placeholder": "Last Name",
"login-cta": "Sign in or Sign up now:",
Expand Down
3 changes: 3 additions & 0 deletions public/icons/checkmark-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions public/icons/close-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion public/icons/show.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 3 additions & 7 deletions src/components/Auth/UserAccountModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import Modal from '@/dls/Modal/Modal';
import useSyncUserData from '@/hooks/auth/useSyncUserData';
import ConsentType from '@/types/auth/ConsentType';
import Announcement from 'types/auth/Announcement';
import FormField from 'types/FormField';

const CompleteSignupForm = dynamic(() => import('@/components/Login/CompleteSignupForm'));
const AnnouncementModalBodyResolver = dynamic(
() => import('@/components/Auth/Announcements/AnnouncementModalBodyResolver'),
);
Expand All @@ -18,17 +16,15 @@ const requiredConsentsEnabled = process.env.NEXT_PUBLIC_ENABLE_REQUIRED_CONSENTS
const REQUIRED_CONSENTS = [ConsentType.COMMUNICATION];

type Props = {
requiredFields: FormField[];
announcement: Announcement;
consents: Record<string, boolean>;
};

const UserAccountModal: React.FC<Props> = ({ requiredFields, announcement, consents }) => {
const UserAccountModal: React.FC<Props> = ({ announcement, consents }) => {
useSyncUserData();

let modalBody;
if (requiredFields && requiredFields?.length !== 0) {
modalBody = <CompleteSignupForm requiredFields={requiredFields} />;
} else if (announcement) {
if (announcement) {
modalBody = <AnnouncementModalBodyResolver announcement={announcement} />;
} else if (requiredConsentsEnabled && consents) {
const missingConsents = REQUIRED_CONSENTS.filter(
Expand Down
2 changes: 1 addition & 1 deletion src/components/Fonts/FontPreLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const SURAH_NAMES_FONT = {

const LOCALE_PRELOADED_FONTS = {
[DEFAULT_LOCALE]: [
{ type: 'font/woff2', location: '/fonts/lang/Figtree/Figtree.ttf' },
{ type: 'font/ttf', location: '/fonts/lang/Figtree/Figtree.ttf' },
{ ...SURAH_NAMES_FONT },
],
ar: [
Expand Down
22 changes: 15 additions & 7 deletions src/components/FormBuilder/FormBuilder.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-lines */
import classNames from 'classnames';
import { Controller, useForm } from 'react-hook-form';

Expand All @@ -20,6 +21,7 @@ type FormBuilderProps<T> = {
actionText?: string;
actionProps?: ButtonProps;
renderAction?: (props: ButtonProps) => React.ReactNode;
shouldSkipValidation?: boolean;
};

/**
Expand Down Expand Up @@ -51,6 +53,7 @@ const FormBuilder = <T,>({
actionProps = {},
isSubmitting,
renderAction,
shouldSkipValidation,
}: FormBuilderProps<T>) => {
const { handleSubmit, control, setError } = useForm({ mode: 'onBlur' });

Expand All @@ -67,16 +70,21 @@ const FormBuilder = <T,>({
}
};

const renderError = (error: any, errorClassName?: string) =>
error && <span className={classNames(styles.errorText, errorClassName)}>{error.message}</span>;
const renderExtraSection = (formField: FormBuilderFormField, value: string) => {
if (!formField.extraSection) return null;
if (typeof formField.extraSection === 'function') {
return formField.extraSection(value);
}
return formField.extraSection;
return typeof formField.extraSection === 'function'
? formField.extraSection(value)
: formField.extraSection;
};

return (
<form className={styles.container} onSubmit={handleSubmit(internalOnSubmit)}>
<form
className={styles.container}
onSubmit={handleSubmit(internalOnSubmit)}
noValidate={shouldSkipValidation}
>
{formFields?.map((formField) => {
return (
<Controller
Expand All @@ -94,7 +102,7 @@ const FormBuilder = <T,>({
onChange: field.onChange,
placeholder: formField.placeholder,
})}
{error && <span className={styles.errorText}>{error.message}</span>}
{renderError(error, formField.errorClassName)}
{renderExtraSection(formField, field.value)}
</div>
);
Expand Down Expand Up @@ -128,7 +136,7 @@ const FormBuilder = <T,>({
return (
<div className={classNames(styles.inputContainer, formField.containerClassName)}>
<InputField {...inputFieldProps} />
{error && <span className={styles.errorText}>{error.message}</span>}
{renderError(error, formField.errorClassName)}
{renderExtraSection(formField, field.value)}
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/components/FormBuilder/FormBuilderTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type FormBuilderFormField = Pick<FormField, 'field' | 'type'> & {
placeholder?: string;
rules?: FormBuilderFieldRule[];
containerClassName?: string;
errorClassName?: string;
checked?: boolean;
fieldSetLegend?: string;
onChange?: (value: unknown) => void;
Expand Down
14 changes: 8 additions & 6 deletions src/components/Login/AuthHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { FC } from 'react';

import classNames from 'classnames';

import styles from './login.module.scss';

import QuranLogo from '@/icons/logo_main.svg';
import QRColoredLogo from '@/icons/qr-colored.svg';
import QuranReflectLogo from '@/icons/qr-logo.svg';
import QRLogo from '@/icons/qr-logo.svg';

const AuthHeader: FC = () => {
return (
<>
<div className={styles.authLogos}>
<QuranLogo />
<div className={styles.qrLogos}>
<QRColoredLogo />
<QuranReflectLogo />
<QuranLogo height={20} />
<div className={classNames(styles.reflectLogos, styles.scaleDown)}>
<QRColoredLogo className={styles.reflectLogo} />
<QRLogo className={styles.reflectLogo} />
</div>
</div>
<hr className={styles.serviceDivider} />
<hr className={styles.divider} />
</>
);
};
Expand Down
31 changes: 31 additions & 0 deletions src/components/Login/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { FC } from 'react';

import useTranslation from 'next-translate/useTranslation';

import styles from './login.module.scss';

import Button, { ButtonType, ButtonVariant } from '@/components/dls/Button/Button';
import ArrowLeft from '@/icons/west.svg';

interface Props {
onClick: () => void;
label?: string;
}

const BackButton: FC<Props> = ({ onClick, label }) => {
const { t } = useTranslation('common');

return (
<Button
onClick={onClick}
className={styles.backButton}
prefix={<ArrowLeft />}
type={ButtonType.Inverse}
variant={ButtonVariant.Ghost}
>
{label || t('back')}
</Button>
);
};

export default BackButton;
23 changes: 23 additions & 0 deletions src/components/Login/BenefitsSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { FC } from 'react';

import Feature from './Feature';
import styles from './login.module.scss';

interface Benefit {
id: string;
label: string;
}

interface BenefitsSectionProps {
benefits: Benefit[];
}

const BenefitsSection: FC<BenefitsSectionProps> = ({ benefits }) => (
<div className={styles.benefits}>
{benefits.map(({ id, label }) => (
<Feature key={id} label={label} />
))}
</div>
);

export default BenefitsSection;
Loading