Update move to react hook form, rename allowedSignUpDomain

This commit is contained in:
Salman
2024-02-12 04:09:46 +05:30
parent 2ef8781378
commit 0fb87ab05f
9 changed files with 100 additions and 63 deletions
@@ -7,7 +7,7 @@ export async function up(knex: Knex): Promise<void> {
if (isTablePresent) { if (isTablePresent) {
await knex.schema.alterTable(TableName.SuperAdmin, (t) => { await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
t.boolean("inviteOnlySignUp").defaultTo(false); t.boolean("inviteOnlySignUp").defaultTo(false);
t.string("allowSpecificDomainSignUp"); t.string("allowedSignUpDomain");
}); });
} }
} }
@@ -19,9 +19,9 @@ export async function down(knex: Knex): Promise<void> {
}); });
} }
if (await knex.schema.hasColumn(TableName.SuperAdmin, "allowSpecificDomainSignUp")) { if (await knex.schema.hasColumn(TableName.SuperAdmin, "allowedSignUpDomain")) {
await knex.schema.alterTable(TableName.SuperAdmin, (t) => { await knex.schema.alterTable(TableName.SuperAdmin, (t) => {
t.dropColumn("allowSpecificDomainSignUp"); t.dropColumn("allowedSignUpDomain");
}); });
} }
} }
+1 -1
View File
@@ -12,7 +12,7 @@ export const SuperAdminSchema = z.object({
initialized: z.boolean().default(false).nullable().optional(), initialized: z.boolean().default(false).nullable().optional(),
allowSignUp: z.boolean().default(true).nullable().optional(), allowSignUp: z.boolean().default(true).nullable().optional(),
inviteOnlySignUp: z.boolean().default(false).nullable().optional(), inviteOnlySignUp: z.boolean().default(false).nullable().optional(),
allowSpecificDomainSignUp: z.string().nullable().optional(), allowedSignUpDomain: z.string().nullable().optional(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date() updatedAt: z.date()
}); });
+1 -1
View File
@@ -33,7 +33,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
body: z.object({ body: z.object({
allowSignUp: z.boolean().optional(), allowSignUp: z.boolean().optional(),
inviteOnlySignUp: z.boolean().optional(), inviteOnlySignUp: z.boolean().optional(),
allowSpecificDomainSignUp: z.string().optional() allowedSignUpDomain: z.string().optional()
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -28,9 +28,9 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
const { email } = req.body; const { email } = req.body;
const serverCfg = await getServerCfg(); const serverCfg = await getServerCfg();
if (serverCfg?.allowSpecificDomainSignUp) { if (serverCfg?.allowedSignUpDomain) {
const domain = email.split("@")[1]; const domain = email.split("@")[1];
const allowedDomains = serverCfg.allowSpecificDomainSignUp.split(",").map((e) => e.trim()); const allowedDomains = serverCfg.allowedSignUpDomain.split(",").map((e) => e.trim());
if (!allowedDomains.includes(domain)) { if (!allowedDomains.includes(domain)) {
throw new BadRequestError({ throw new BadRequestError({
message: `Email with a domain (@${domain}) is not supported` message: `Email with a domain (@${domain}) is not supported`
@@ -273,9 +273,9 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
if (!serverCfg?.allowSignUp) if (!serverCfg?.allowSignUp)
throw new BadRequestError({ message: "User signup disabled", name: "Oauth 2 login" }); throw new BadRequestError({ message: "User signup disabled", name: "Oauth 2 login" });
if (serverCfg?.allowSpecificDomainSignUp) { if (serverCfg?.allowedSignUpDomain) {
const domain = email.split("@")[1]; const domain = email.split("@")[1];
const allowedDomains = serverCfg.allowSpecificDomainSignUp.split(",").map((e) => e.trim()); const allowedDomains = serverCfg.allowedSignUpDomain.split(",").map((e) => e.trim());
if (!allowedDomains.includes(domain)) if (!allowedDomains.includes(domain))
throw new BadRequestError({ throw new BadRequestError({
message: `Email with a domain (@${domain}) is not supported`, message: `Email with a domain (@${domain}) is not supported`,
+1 -1
View File
@@ -2,7 +2,7 @@ export type TServerConfig = {
initialized: boolean; initialized: boolean;
allowSignUp: boolean; allowSignUp: boolean;
inviteOnlySignUp: boolean; inviteOnlySignUp: boolean;
allowSpecificDomainSignUp?: string; allowedSignUpDomain?: string;
isMigrationModeOn?: boolean; isMigrationModeOn?: boolean;
}; };
+1 -1
View File
@@ -2,7 +2,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
import crypto from "crypto"; import crypto from "crypto";
import { useEffect,useState } from "react"; import { useEffect, useState } from "react";
import Head from "next/head"; import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
@@ -226,7 +226,7 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }:
</Button> </Button>
</div> </div>
{!isLoading && loginError && <Error text={t("login.error-login") ?? ""} />} {!isLoading && loginError && <Error text={t("login.error-login") ?? ""} />}
{config.allowSignUp ? ( {config.allowSignUp && !config.inviteOnlySignUp ? (
<div className="mt-6 flex flex-row text-sm text-bunker-400"> <div className="mt-6 flex flex-row text-sm text-bunker-400">
<Link href="/signup"> <Link href="/signup">
<span className="cursor-pointer duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4"> <span className="cursor-pointer duration-200 hover:text-bunker-200 hover:underline hover:decoration-primary-700 hover:underline-offset-4">
@@ -1,7 +1,10 @@
import { useEffect, useState } from "react"; import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faAt } from "@fortawesome/free-solid-svg-icons"; import { faAt } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { import {
@@ -23,15 +26,37 @@ enum TabSections {
Settings = "settings" Settings = "settings"
} }
type SignUpMode = "disabled" | "invite-only" | "anyone"; const formSchema = yup.object({
signUpMode: yup
.string()
.oneOf(["disabled", "invite-only", "anyone"])
.required(),
allowedSignUpDomain: yup.string().optional()
});
type TDashboardForm = yup.InferType<typeof formSchema>;
export const AdminDashboardPage = () => { export const AdminDashboardPage = () => {
const router = useRouter(); const router = useRouter();
const data = useServerConfig(); const data = useServerConfig();
const [signUpMode, setSignUpMode] = useState<SignUpMode>("invite-only");
const [allowSpecificDomain, setAllowSpecificDomain] = useState<string | undefined>();
const { config } = data; const { config } = data;
const signUpStatus = config.allowSignUp
? config.inviteOnlySignUp && "invite-only"
: "disabled";
const signUpType = signUpStatus || "anyone";
const { control, handleSubmit, watch } = useForm<TDashboardForm>({
resolver: yupResolver(formSchema),
defaultValues: {
signUpMode: signUpType,
allowedSignUpDomain: config.allowedSignUpDomain
}
});
const signupMode = watch("signUpMode");
const { user, isLoading: isUserLoading } = useUser(); const { user, isLoading: isUserLoading } = useUser();
const { orgs } = useOrganization(); const { orgs } = useOrganization();
const { mutate: updateServerConfig } = useUpdateServerConfig(); const { mutate: updateServerConfig } = useUpdateServerConfig();
@@ -49,29 +74,15 @@ export const AdminDashboardPage = () => {
} }
}, [isNotAllowed, isUserLoading]); }, [isNotAllowed, isUserLoading]);
useEffect(() => { const onFormSubmit = async (formData: TDashboardForm) => {
if (!config.allowSignUp) {
setSignUpMode("disabled");
return;
}
if (config.inviteOnlySignUp) {
setSignUpMode("invite-only");
} else {
setSignUpMode("anyone");
}
if (config.allowSpecificDomainSignUp) {
setAllowSpecificDomain(config.allowSpecificDomainSignUp);
}
}, [config]);
const handleSubmit = async () => {
try { try {
config.allowSignUp = signUpMode !== "disabled"; const { signUpMode, allowedSignUpDomain } = formData;
config.inviteOnlySignUp = signUpMode === "invite-only";
config.allowSpecificDomainSignUp = signUpMode === "anyone" ? allowSpecificDomain : "";
await updateServerConfig(config); await updateServerConfig({
allowSignUp: signUpMode !== "disabled",
inviteOnlySignUp: signUpMode === "invite-only",
allowedSignUpDomain: signUpMode === "anyone" ? allowedSignUpDomain : ""
});
createNotification({ createNotification({
text: "Successfully changed sign up setting.", text: "Successfully changed sign up setting.",
@@ -86,6 +97,8 @@ export const AdminDashboardPage = () => {
} }
}; };
return ( return (
<div className="container mx-auto max-w-7xl px-4 pb-12 text-white dark:[color-scheme:dark]"> <div className="container mx-auto max-w-7xl px-4 pb-12 text-white dark:[color-scheme:dark]">
<div className="mx-auto mb-6 w-full max-w-7xl pt-6"> <div className="mx-auto mb-6 w-full max-w-7xl pt-6">
@@ -105,46 +118,70 @@ export const AdminDashboardPage = () => {
</div> </div>
</TabList> </TabList>
<TabPanel value={TabSections.Settings}> <TabPanel value={TabSections.Settings}>
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"> <form
className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
onSubmit={handleSubmit(onFormSubmit)}
>
<div className="flex justify-between"> <div className="flex justify-between">
<div className="mb-4 text-xl font-semibold text-mineshaft-100"> <div className="mb-4 text-xl font-semibold text-mineshaft-100">
Allow user to Sign Up Allow user to Sign Up
</div> </div>
<Select <Controller
className="w-72 bg-mineshaft-700" control={control}
dropdownContainerClassName="bg-mineshaft-700" name="signUpMode"
onValueChange={(state) => setSignUpMode(state as SignUpMode)} render={({ field: { onChange, ...field }, fieldState: { error } }) => (
value={signUpMode} <FormControl
isDisabled={isNotAllowed} className="max-w-72 w-72"
> errorText={error?.message}
<SelectItem value="disabled">Disabled</SelectItem> isError={Boolean(error)}
<SelectItem value="invite-only">Invite Only</SelectItem> >
<SelectItem value="anyone">Anyone</SelectItem> <Select
</Select> className="w-72 bg-mineshaft-700"
dropdownContainerClassName="bg-mineshaft-700"
defaultValue={field.value}
onValueChange={(e) => onChange(e)}
{...field}
>
<SelectItem value="disabled">Disabled</SelectItem>
<SelectItem value="invite-only">Invite Only</SelectItem>
<SelectItem value="anyone">Anyone</SelectItem>
</Select>
</FormControl>
)}
/>
</div> </div>
{signUpMode === "anyone" && ( {signupMode === "anyone" && (
<div className="mt-4 flex items-center justify-between"> <div className="mt-4 flex items-center justify-between">
<div className="mb-4 flex text-mineshaft-100"> <div className="mb-4 flex text-mineshaft-100">
Allow email with only specific domain(s) Allow email with only specific domain(s)
</div> </div>
<FormControl label="Leave blank to allow any domain handle" className="w-72"> <Controller
<div> control={control}
<Input defaultValue=""
placeholder="domain.com, domain2.com" name="allowedSignUpDomain"
leftIcon={<FontAwesomeIcon icon={faAt} />} render={({ field, fieldState: { error } }) => (
value={allowSpecificDomain} <FormControl
onChange={(ev) => setAllowSpecificDomain(ev.target.value)} label="Leave blank to allow any domain handle"
/> className="w-72"
</div> isError={Boolean(error)}
</FormControl> errorText={error?.message}
>
<Input
{...field}
placeholder="domain.com, domain2.com"
leftIcon={<FontAwesomeIcon icon={faAt} />}
/>
</FormControl>
)}
/>
</div> </div>
)} )}
<Button colorSchema="primary" variant="outline_bg" onClick={handleSubmit}> <Button colorSchema="primary" variant="outline_bg" type="submit">
Save Save
</Button> </Button>
</div> </form>
</TabPanel> </TabPanel>
</Tabs> </Tabs>
</div> </div>