-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* support page with multiple forms support * initially, a DMCA form has been added Signed-off-by: GitHub <noreply@github.com>
- Loading branch information
1 parent
8f0f540
commit ea90d45
Showing
11 changed files
with
532 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import Footer from "@/components/Layout/Footer"; | ||
import { PropsWithChildren } from "react"; | ||
|
||
export default function Layout({ children }: PropsWithChildren) { | ||
return ( | ||
<> | ||
<div className="min-h-screen block">{children}</div> | ||
<Footer /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import SupportForm from "@/features/SupportForm/SupportForm"; | ||
import { ServerComponentProps } from "@/types/ServerComponentProps"; | ||
import { Spacer } from "@nextui-org/react"; | ||
|
||
export default function Page({ searchParams }: ServerComponentProps) { | ||
const form = searchParams?.form; | ||
|
||
return ( | ||
<main className="flex items-center justify-center py-5 lg:py-10 px-3"> | ||
<div className="md:w-96 lg:w-1/2 xl:w-1/3"> | ||
<h1 className="text-4xl font-bold">Support</h1> | ||
<p> | ||
You can contact our support team by filling out the form | ||
below. | ||
</p> | ||
|
||
<Spacer y={5} /> | ||
<SupportForm form={form} /> | ||
</div> | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { Input, Spacer } from "@nextui-org/react"; | ||
import { | ||
Control, | ||
FieldValues, | ||
FormState, | ||
Path, | ||
UseFormRegister, | ||
} from "react-hook-form"; | ||
|
||
type CommonFieldsProps<T extends FieldValues> = { | ||
control: Control<T>; | ||
register: UseFormRegister<T>; | ||
formState: FormState<T>; | ||
}; | ||
|
||
const CommonFields = <T extends FieldValues>({ | ||
control, | ||
register, | ||
formState, | ||
}: CommonFieldsProps<T>) => { | ||
return ( | ||
<> | ||
<Input | ||
label="Your name" | ||
isInvalid={Boolean(formState.errors.name)} | ||
errorMessage={formState.errors.name?.message?.toString()} | ||
{...register("name" as Path<T>)} | ||
/> | ||
<Spacer y={2} /> | ||
<Input | ||
label="Email address" | ||
isInvalid={Boolean(formState.errors.email)} | ||
errorMessage={formState.errors.email?.message?.toString()} | ||
{...register("email" as Path<T>)} | ||
/> | ||
<p className="text-[#999] text-xs ml-1 mt-1"> | ||
We’ll use this email address to contact you back if | ||
necessary. | ||
</p> | ||
<div className="w-full h-[1px] bg-neutral-300 dark:bg-neutral-700 block my-5"></div> | ||
</> | ||
); | ||
}; | ||
|
||
export default CommonFields; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { Input, Radio, RadioGroup, Spacer, Textarea } from "@nextui-org/react"; | ||
import clsx from "clsx"; | ||
import { useRef, useState, type FC } from "react"; | ||
import { Controller, Form, useForm } from "react-hook-form"; | ||
import { z } from "zod"; | ||
import CommonFields from "./CommonFields"; | ||
import DMCASwornStatements from "./DMCASwornStatements"; | ||
import SubmitButton from "./SubmitButton"; | ||
import { DMCAFormSchema } from "./SupportFormSchemas"; | ||
|
||
type DMCAFormProps = {}; | ||
|
||
const DMCAForm: FC<DMCAFormProps> = (props) => { | ||
const [swornStatementsError, setSwornStatementsError] = useState< | ||
string | null | ||
>(null); | ||
const { control, register, formState } = useForm< | ||
z.infer<typeof DMCAFormSchema> | ||
>({ | ||
resolver: zodResolver(DMCAFormSchema), | ||
}); | ||
const swornStatementsRef = useRef<[boolean, boolean, boolean]>([ | ||
false, | ||
false, | ||
false, | ||
]); | ||
|
||
const handleSubmit = ({ | ||
data, | ||
}: { | ||
data: z.infer<typeof DMCAFormSchema>; | ||
}) => { | ||
if (!swornStatementsRef.current.every(Boolean)) { | ||
setSwornStatementsError( | ||
"Please agree to all the sworn statements.", | ||
); | ||
return; | ||
} | ||
|
||
setSwornStatementsError(null); | ||
console.log(data); | ||
}; | ||
|
||
return ( | ||
<Form control={control} onSubmit={handleSubmit}> | ||
<CommonFields | ||
control={control} | ||
register={register} | ||
formState={formState} | ||
/> | ||
|
||
<h2 className="text-2xl">Details of the Infringement</h2> | ||
<p className="text-[#999] text-sm mb-5"> | ||
Please provide the following details about the infringement. | ||
</p> | ||
|
||
<Controller | ||
name="infringingURLs" | ||
control={control} | ||
render={({ field, fieldState }) => ( | ||
<Textarea | ||
label="Infringing URLs" | ||
isInvalid={Boolean(fieldState.error)} | ||
errorMessage={fieldState.error?.message?.toString()} | ||
onBlur={field.onBlur} | ||
onValueChange={(value) => { | ||
field.onChange( | ||
(value || "") | ||
.split("\n") | ||
.map((str) => str.trim()) | ||
.filter(Boolean), | ||
); | ||
}} | ||
/> | ||
)} | ||
/> | ||
<p className="text-[#999] text-xs ml-1 mt-1"> | ||
Please enter the URLs that are infringing your content. You can | ||
enter multiple URLs by separating them with a new line. | ||
<br /> | ||
If the infringing content is a Discord Message, please provide | ||
the message link. | ||
</p> | ||
|
||
<Spacer y={3} /> | ||
<Controller | ||
name="originalContentURLs" | ||
control={control} | ||
render={({ field, fieldState }) => ( | ||
<Textarea | ||
label="URLs to the Original Content" | ||
isInvalid={Boolean(fieldState.error)} | ||
errorMessage={fieldState.error?.message?.toString()} | ||
onBlur={field.onBlur} | ||
onValueChange={(value) => { | ||
field.onChange( | ||
(value || "") | ||
.split("\n") | ||
.map((str) => str.trim()) | ||
.filter(Boolean), | ||
); | ||
}} | ||
/> | ||
)} | ||
/> | ||
<p className="text-[#999] text-xs ml-1 mt-1"> | ||
Please enter the URLs to the original content. You can enter | ||
multiple URLs by separating them with a new line. | ||
</p> | ||
|
||
<Spacer y={3} /> | ||
<Textarea | ||
label="Description of the Infringement" | ||
isInvalid={Boolean(formState.errors.description)} | ||
errorMessage={formState.errors.description?.message?.toString()} | ||
{...register("description")} | ||
/> | ||
|
||
<h2 className="text-2xl mt-7">Your Information</h2> | ||
<p className="text-[#999] text-sm mb-5"> | ||
Please provide your information below. | ||
</p> | ||
|
||
<Spacer y={3} /> | ||
<Input | ||
label="Your Full Legal Name" | ||
isInvalid={Boolean(formState.errors.legalName)} | ||
errorMessage={formState.errors.legalName?.message?.toString()} | ||
{...register("legalName")} | ||
/> | ||
|
||
<Spacer y={3} /> | ||
<Input | ||
label="Your Company Name (if applicable)" | ||
isInvalid={Boolean(formState.errors.companyName)} | ||
errorMessage={formState.errors.companyName?.message?.toString()} | ||
{...register("companyName")} | ||
/> | ||
|
||
<Spacer y={3} /> | ||
<Input | ||
label="Your Position in the Company (if applicable)" | ||
isInvalid={Boolean(formState.errors.position)} | ||
errorMessage={formState.errors.position?.message?.toString()} | ||
{...register("position")} | ||
/> | ||
|
||
<Spacer y={3} /> | ||
<Controller | ||
name="actingOnBehalfOf" | ||
control={control} | ||
render={({ field, fieldState }) => ( | ||
<> | ||
<RadioGroup | ||
label="I am acting on behalf of:" | ||
isInvalid={Boolean(fieldState.error)} | ||
errorMessage={fieldState.error?.message?.toString()} | ||
onValueChange={field.onChange} | ||
> | ||
<Radio value="myself">Myself</Radio> | ||
<Radio value="company">My Company</Radio> | ||
<Radio value="client">My Client</Radio> | ||
<Radio value="other"> | ||
Other (please specify below) | ||
</Radio> | ||
</RadioGroup> | ||
|
||
<Input | ||
label="On behalf of" | ||
isInvalid={Boolean( | ||
formState.errors.actingOnBehalfOfOther, | ||
)} | ||
errorMessage={formState.errors.actingOnBehalfOfOther?.message?.toString()} | ||
className={clsx( | ||
"mt-3", | ||
field.value === "other" ? "" : "hidden", | ||
)} | ||
{...register("actingOnBehalfOfOther")} | ||
/> | ||
</> | ||
)} | ||
/> | ||
|
||
<Spacer y={5} /> | ||
<DMCASwornStatements | ||
onValueChange={(index, values) => { | ||
swornStatementsRef.current[index] = values; | ||
}} | ||
/> | ||
{swornStatementsError && ( | ||
<p className="text-red-500 text-sm mt-2"> | ||
{swornStatementsError} | ||
</p> | ||
)} | ||
|
||
<Spacer y={5} /> | ||
<h2 className="text-2xl">Signature</h2> | ||
<p className="text-[#999] text-sm mb-5">Please sign this form.</p> | ||
|
||
<Spacer y={3} /> | ||
<Input | ||
label="Your Signature" | ||
isInvalid={Boolean(formState.errors.signature)} | ||
errorMessage={formState.errors.signature?.message?.toString()} | ||
{...register("signature")} | ||
/> | ||
|
||
<SubmitButton /> | ||
</Form> | ||
); | ||
}; | ||
|
||
export default DMCAForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Checkbox } from "@nextui-org/react"; | ||
import { type FC } from "react"; | ||
|
||
type DMCASwornStatementsProps = { | ||
onValueChange: (index: number, value: boolean) => void; | ||
}; | ||
|
||
const DMCASwornStatements: FC<DMCASwornStatementsProps> = ({ | ||
onValueChange, | ||
}) => { | ||
return ( | ||
<div> | ||
<Checkbox onValueChange={(value) => onValueChange(0, value)}> | ||
<span className="text-sm"> | ||
I have a good faith belief that the use of the material in | ||
the manner complained of is not authorized by the copyright | ||
owner, its agent, or the law. | ||
</span> | ||
</Checkbox> | ||
|
||
<Checkbox onValueChange={(value) => onValueChange(1, value)}> | ||
<span className="text-sm"> | ||
I swear, under penalty of perjury, that the information in | ||
the notification is accurate, and that I am the owner of an | ||
exclusive right that is allegedly infringed. | ||
</span> | ||
</Checkbox> | ||
|
||
<Checkbox onValueChange={(value) => onValueChange(2, value)}> | ||
<span className="text-sm"> | ||
I acknowledge that I may be liable for damages if I | ||
knowingly materially misrepresent that material or activity | ||
is infringing. | ||
</span> | ||
</Checkbox> | ||
</div> | ||
); | ||
}; | ||
|
||
export default DMCASwornStatements; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { type FC } from "react"; | ||
import { Form, useForm } from "react-hook-form"; | ||
import { z } from "zod"; | ||
import CommonFields from "./CommonFields"; | ||
import SubmitButton from "./SubmitButton"; | ||
import { GeneralHelpFormSchema } from "./SupportFormSchemas"; | ||
|
||
type GeneralHelpFormProps = {}; | ||
|
||
const GeneralHelpForm: FC<GeneralHelpFormProps> = (props) => { | ||
const { control, register, formState } = useForm< | ||
z.infer<typeof GeneralHelpFormSchema> | ||
>({ | ||
resolver: zodResolver(GeneralHelpFormSchema), | ||
}); | ||
|
||
return ( | ||
<Form control={control}> | ||
<CommonFields | ||
control={control} | ||
register={register} | ||
formState={formState} | ||
/> | ||
<SubmitButton /> | ||
</Form> | ||
); | ||
}; | ||
|
||
export default GeneralHelpForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Button, Spacer } from "@nextui-org/react"; | ||
|
||
const SubmitButton = () => { | ||
return ( | ||
<> | ||
<Spacer y={5} /> | ||
<Button type="submit" variant="flat" fullWidth> | ||
Submit | ||
</Button> | ||
</> | ||
); | ||
}; | ||
|
||
export default SubmitButton; |
Oops, something went wrong.