Skip to content

Commit

Permalink
fix: some changes updated regarding to reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
ChengShi-1 committed Feb 26, 2025
1 parent 935d3ed commit 286305a
Show file tree
Hide file tree
Showing 19 changed files with 166 additions and 199 deletions.
2 changes: 1 addition & 1 deletion packages/design-system/src/lib/components/alert/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface AlertProps {
variant: AlertVariant
dismissible?: boolean
customHeading?: string
children?: ReactNode
children: ReactNode
}

function Alert({ variant, dismissible = true, customHeading, children }: AlertProps) {
Expand Down
26 changes: 0 additions & 26 deletions public/locales/en/contact.json

This file was deleted.

21 changes: 16 additions & 5 deletions public/locales/en/shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,22 @@
"required": "Validation is required.",
"invalid": "Incorrect answer.",
"onlyNumber": "Only numbers are allowed.",
"maxLength": "Answer cannot exceed 10."
"maxLength": "Answer cannot exceed {{maxLength}} ."
},
"email": { "required": "Email is required.", "maxLength": "Email cannot exceed 255." },
"subject": { "required": "Subject is required.", "maxLength": "Subject cannot exceed 255." },
"message": { "required": "Message is required.", "maxLength": "Message cannot exceed 255." }
}
"email": {
"invalid": "Invalid email format.",
"required": "Email is required.",
"maxLength": "Email cannot exceed {{maxLength}} ."
},
"subject": {
"required": "Subject is required.",
"maxLength": "Subject cannot exceed {{maxLength}} ."
},
"message": {
"required": "Message is required.",
"maxLength": "Message cannot exceed {{maxLength}} ."
}
},
"defaultFeedbackSubmitError": "An error occurred while submitting your feedback. Please try again later."
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface Contact {
export interface ContactResponse {
subject: string
body: string
fromEmail: string
Expand Down
4 changes: 2 additions & 2 deletions src/contact/domain/repositories/ContactRepository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FeedbackDTO } from '../useCases/FeedbackDTO'
import { Contact } from '../models/Contact'
import { ContactResponse } from '../models/ContactResponse'

export interface ContactRepository {
sendFeedbacktoOwners: (feedbackDTO: FeedbackDTO) => Promise<Contact[]>
sendFeedbacktoOwners: (feedbackDTO: FeedbackDTO) => Promise<ContactResponse[]>
}
4 changes: 2 additions & 2 deletions src/contact/domain/useCases/sendFeedbacktoOwners.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ContactRepository } from '../repositories/ContactRepository'
import { WriteError } from '@iqss/dataverse-client-javascript'
import { FeedbackDTO } from '../useCases/FeedbackDTO'
import { Contact } from '../models/Contact'
import { ContactResponse } from '../models/ContactResponse'

export async function sendFeedbacktoOwners(
ContactRepository: ContactRepository,
FeedbackDTO: FeedbackDTO
): Promise<Contact[]> {
): Promise<ContactResponse[]> {
return ContactRepository.sendFeedbacktoOwners(FeedbackDTO).catch((error: WriteError) => {
throw new Error(error.message)
})
Expand Down
6 changes: 3 additions & 3 deletions src/contact/infrastructure/ContactJSDataverseRepository.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { submitContactInfo } from '@iqss/dataverse-client-javascript'
import { Contact } from '../domain/models/Contact'
import { ContactResponse } from '../domain/models/ContactResponse'
import { ContactRepository } from '../domain/repositories/ContactRepository'
import { FeedbackDTO } from '../domain/useCases/FeedbackDTO'

export class ContactJSDataverseRepository implements ContactRepository {
async sendFeedbacktoOwners(feedbackDTO: FeedbackDTO): Promise<Contact[]> {
return submitContactInfo.execute(feedbackDTO).then((response: Contact[]) => response)
async sendFeedbacktoOwners(feedbackDTO: FeedbackDTO): Promise<ContactResponse[]> {
return submitContactInfo.execute(feedbackDTO).then((response: ContactResponse[]) => response)
}
}
2 changes: 1 addition & 1 deletion src/sections/collection/Collection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export function Collection({
<div className={styles['right-content']}>
<ContactButton
toContactName={collection.name}
contactObjectType={'collection'}
contactObjectType="collection"
id={collection.id}
contactRepository={contactRepository}
/>
Expand Down
1 change: 1 addition & 0 deletions src/sections/collection/CollectionFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useGetCollectionQueryParams } from './useGetCollectionQueryParams'

const collectionRepository = new CollectionJSDataverseRepository()
const contactRepository = new ContactJSDataverseRepository()

export class CollectionFactory {
static create(): ReactElement {
return <CollectionWithSearchParams />
Expand Down
59 changes: 28 additions & 31 deletions src/sections/shared/contact/contact-modal/contact-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { useForm, FormProvider } from 'react-hook-form'
import { Alert, Button, Modal } from '@iqss/dataverse-design-system'
import { Alert, Button, Modal, Spinner } from '@iqss/dataverse-design-system'
import { FeedbackDTO } from '@/contact/domain/useCases/FeedbackDTO'
import { Captcha } from '@/sections/shared/form/ContactForm/ContactCaptcha'
import { ContactForm } from '@/sections/shared/form/ContactForm/ContactForm'
import { useSession } from '@/sections/session/SessionContext'
import {
useSendFeedbacktoOwners,
SubmissionStatus
} from '@/sections/shared/form/ContactForm/useSendFeedbacktoOwners'
import { useSendFeedbacktoOwners } from '@/sections/shared/form/ContactForm/useSendFeedbacktoOwners'
import { ContactRepository } from '@/contact/domain/repositories/ContactRepository'
import { toast } from 'react-toastify'

Expand Down Expand Up @@ -41,9 +36,17 @@ export const ContactModal = ({
const { t } = useTranslation('shared')
const { user } = useSession()

const { submitForm, submissionStatus, submitError } = useSendFeedbacktoOwners(contactRepository)
const closeModalAndSentToast = () => {
handleClose()
toast.success(t('contact.contactSuccess'))
}

const { submitForm, isSubmittingForm, submitError } = useSendFeedbacktoOwners({
contactRepository,
onSuccessfulSubmit: closeModalAndSentToast
})

const methods = useForm<ContactFormData>({
const formMethods = useForm<ContactFormData>({
defaultValues: {
id: id,
subject: '',
Expand All @@ -62,48 +65,42 @@ export const ContactModal = ({
}

await submitForm(formData)
methods.reset()
}

useEffect(() => {
if (submissionStatus === SubmissionStatus.SubmitComplete) {
handleClose()
toast.success(t('contact.contactSuccess'))
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [submissionStatus])

return (
<Modal show={show} onHide={handleClose} centered>
<Modal
show={show}
onHide={() => {
handleClose()
formMethods.reset()
}}
centered>
<Modal.Header>
<Modal.Title>{title}</Modal.Title>
</Modal.Header>
<Modal.Body>
{submissionStatus === SubmissionStatus.Errored && (
{submitError && (
<Alert variant="danger" dismissible={false}>
{submitError}
</Alert>
)}
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<FormProvider {...formMethods}>
<form onSubmit={formMethods.handleSubmit(onSubmit)}>
<ContactForm isLoggedIn={Boolean(user)} toContactName={toContactName} />
</form>
<Captcha />
</FormProvider>
</Modal.Body>
<Modal.Footer>
<Button
variant="secondary"
type="button"
disabled={submissionStatus === SubmissionStatus.IsSubmitting}
onClick={handleClose}>
<Button variant="secondary" type="button" disabled={isSubmittingForm} onClick={handleClose}>
{t('close')}
</Button>
<Button
type="submit"
onClick={methods.handleSubmit(onSubmit)}
disabled={submissionStatus === SubmissionStatus.IsSubmitting}>
{submissionStatus === SubmissionStatus.IsSubmitting ? t('Submitting') : t('Submit')}
onClick={formMethods.handleSubmit(onSubmit)}
disabled={isSubmittingForm}>
{isSubmittingForm && <Spinner variant="light" animation="border" size="sm" />
? t('Submitting')
: t('Submit')}
</Button>
</Modal.Footer>
</Modal>
Expand Down
76 changes: 34 additions & 42 deletions src/sections/shared/form/ContactForm/ContactCaptcha.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
import { useEffect, useState } from 'react'
import { Controller, useFormContext } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
import { Form, Col, Row } from '@iqss/dataverse-design-system'
import { Form } from '@iqss/dataverse-design-system'
import { Validator } from '@/shared/helpers/Validator'

export function Captcha() {
const { t } = useTranslation('shared')
const { control } = useFormContext()

const [num1, setNum1] = useState(Math.floor(Math.random() * 10))
const [num2, setNum2] = useState(Math.floor(Math.random() * 10))

useEffect(() => {
setNum1(Math.floor(Math.random() * 10))
setNum2(Math.floor(Math.random() * 10))
}, [])
const num1 = Math.floor(Math.random() * 10)
const num2 = Math.floor(Math.random() * 10)

const captchaAnswer = num1 + num2

const captchaRules = {
required: t('contact.validation.captchaInput.required'),
validate: (value: string) => {
if (!/^\d+$/.test(value)) {
if (!Validator.isValidNumber(value)) {
return t('contact.validation.captchaInput.onlyNumber')
}
return parseInt(value, 10) === captchaAnswer || t('contact.validation.captchaInput.invalid')
Expand All @@ -32,38 +27,35 @@ export function Captcha() {
}

return (
<Row className="mb-3">
<Col lg={3}>{''}</Col>
<Col lg={9}>
<Form.Group.Label required>{t('contact.verificationText')}</Form.Group.Label>
<div className="d-flex align-items-center">
<Form.Group.Label style={{ margin: 0 }} data-testid="captchaNumbers">
{num1} + {num2} =
</Form.Group.Label>
<Controller
name="captchaInput"
control={control}
rules={captchaRules}
render={({ field: { onChange, ref, value }, fieldState: { error } }) => (
<>
<Form.Group.Input
data-testid="captchaInput"
value={value as string}
onChange={onChange}
ref={ref}
style={{ width: '20%' }}
type="text"
isInvalid={!!error}
/>
<>
<Form.Group.Label required>{t('contact.verificationText')}</Form.Group.Label>
<div className="d-flex align-items-center">
<Form.Group.Label style={{ margin: 0 }} data-testid="captchaNumbers">
{num1} + {num2} =
</Form.Group.Label>
<Controller
name="captchaInput"
control={control}
rules={captchaRules}
render={({ field: { onChange, ref, value }, fieldState: { error } }) => (
<>
<Form.Group.Input
data-testid="captchaInput"
value={value as string}
onChange={onChange}
ref={ref}
style={{ width: '20%' }}
type="text"
isInvalid={!!error}
/>

<Form.Group.Feedback type="invalid" className="ms-2" style={{ width: '50%' }}>
{error?.message}
</Form.Group.Feedback>
</>
)}
/>
</div>
</Col>
</Row>
<Form.Group.Feedback type="invalid" className="ms-2" style={{ width: '50%' }}>
{error?.message}
</Form.Group.Feedback>
</>
)}
/>
</div>
</>
)
}
18 changes: 12 additions & 6 deletions src/sections/shared/form/ContactForm/ContactForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useTranslation } from 'react-i18next'
import { Controller, useFormContext, UseControllerProps } from 'react-hook-form'
import { Form, Row, Col } from '@iqss/dataverse-design-system'
import { Validator } from '@/shared/helpers/Validator'
import { Captcha } from './ContactCaptcha'

interface ContactFormProps {
isLoggedIn: boolean
Expand All @@ -13,9 +15,10 @@ export function ContactForm({ isLoggedIn, toContactName }: ContactFormProps) {

const emailRules: UseControllerProps['rules'] = {
required: t('contact.validation.email.required'),
pattern: {
value: /^[^@ ]+@[^@ ]+\.[^@ ]+$/,
message: 'Invalid email format'
validate: (value: string) => {
if (!Validator.isValidEmail(value)) {
return t('contact.validation.email.invalid')
}
},
maxLength: {
value: 255,
Expand Down Expand Up @@ -45,7 +48,6 @@ export function ContactForm({ isLoggedIn, toContactName }: ContactFormProps) {
<Form.Group.Text>{toContactName} Contact</Form.Group.Text>
</Col>
</Row>

<Row className="mb-3">
<Col lg={3}>
<Form.Group.Label required>From</Form.Group.Label>
Expand Down Expand Up @@ -73,7 +75,6 @@ export function ContactForm({ isLoggedIn, toContactName }: ContactFormProps) {
/>
</Col>
</Row>

<Row className="mb-3">
<Col lg={3}>
<Form.Group.Label required>{t('contact.subject')}</Form.Group.Label>
Expand All @@ -99,7 +100,6 @@ export function ContactForm({ isLoggedIn, toContactName }: ContactFormProps) {
/>
</Col>
</Row>

<Row className="mb-3">
<Col lg={3}>
<Form.Group.Label required>{t('contact.message')}</Form.Group.Label>
Expand All @@ -123,6 +123,12 @@ export function ContactForm({ isLoggedIn, toContactName }: ContactFormProps) {
)}
/>
</Col>
</Row>{' '}
<Row className="mb-3">
<Col lg={3}>{''}</Col>
<Col lg={9}>
<Captcha />
</Col>
</Row>
</>
)
Expand Down
Loading

0 comments on commit 286305a

Please sign in to comment.