diff --git a/bun.lockb b/bun.lockb
index c3bb01f..434348d 100644
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index c3618b6..4da62df 100644
--- a/package.json
+++ b/package.json
@@ -30,11 +30,13 @@
"clsx": "^2.1.1",
"cmdk": "1.0.0",
"framer-motion": "^11.5.4",
+ "input-otp": "^1.2.4",
"lossless-json": "^4.0.2",
"lucide-react": "^0.441.0",
"next": "14.2.8",
"next-client-cookies": "^1.1.1",
"next-themes": "^0.3.0",
+ "qrcode.react": "^4.0.1",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.53.0",
diff --git a/src/app/(pages)/dashboard/user/profile/page.tsx b/src/app/(pages)/dashboard/user/profile/page.tsx
index 07936dc..47758ff 100644
--- a/src/app/(pages)/dashboard/user/profile/page.tsx
+++ b/src/app/(pages)/dashboard/user/profile/page.tsx
@@ -13,10 +13,10 @@ import { User } from "@/app/types/user/user";
import { useUserContext } from "@/app/provider/user-provider";
import { UserState } from "@/app/store/user-store";
import { Separator } from "@/components/ui/separator";
-import AvatarSetting from "@/components/dashboard/user/avatar-setting";
-import UsernameSetting from "@/components/dashboard/user/username-setting";
-import EmailSetting from "@/components/dashboard/user/email-setting";
-import TierSetting from "@/components/dashboard/user/tier-setting";
+import AvatarSetting from "@/components/dashboard/user/profile/avatar-setting";
+import UsernameSetting from "@/components/dashboard/user/profile/username-setting";
+import EmailSetting from "@/components/dashboard/user/profile/email-setting";
+import TierSetting from "@/components/dashboard/user/profile/tier-setting";
/**
* The user profile page.
diff --git a/src/app/(pages)/dashboard/user/settings/page.tsx b/src/app/(pages)/dashboard/user/settings/page.tsx
index 682d8e6..a30d346 100644
--- a/src/app/(pages)/dashboard/user/settings/page.tsx
+++ b/src/app/(pages)/dashboard/user/settings/page.tsx
@@ -13,6 +13,7 @@ import { User } from "@/app/types/user/user";
import { useUserContext } from "@/app/provider/user-provider";
import { UserState } from "@/app/store/user-store";
import { Separator } from "@/components/ui/separator";
+import TFASetting from "@/components/dashboard/user/settings/tfa/tfa-setting";
/**
* The user settings page.
@@ -26,7 +27,7 @@ const UserSettingsPage = (): ReactElement => (
{/* Content */}
- Hello World
+
);
diff --git a/src/app/types/user/response/user-setup-tfa-response.ts b/src/app/types/user/response/user-setup-tfa-response.ts
new file mode 100644
index 0000000..f81026a
--- /dev/null
+++ b/src/app/types/user/response/user-setup-tfa-response.ts
@@ -0,0 +1,16 @@
+/**
+ * The response for when a {@link User}
+ * initializes the setup of two-factor
+ * authentication.
+ */
+export type UserSetupTfaResponse = {
+ /**
+ * The TFA secret.
+ */
+ secret: string;
+
+ /**
+ * The URL to the QR code.
+ */
+ qrCodeUrl: string;
+};
diff --git a/src/app/types/user/user-flag.ts b/src/app/types/user/user-flag.ts
index 7efe8f7..b48aa38 100644
--- a/src/app/types/user/user-flag.ts
+++ b/src/app/types/user/user-flag.ts
@@ -2,7 +2,23 @@
* Flags for a {@link User}.
*/
export enum UserFlag {
+ /**
+ * The user is disabled.
+ */
DISABLED = 0,
+
+ /**
+ * The user completed the onboarding process.
+ */
COMPLETED_ONBOARDING = 1,
- ADMINISTRATOR = 2,
+
+ /**
+ * The user has two-factor auth enabled.
+ */
+ TFA_ENABLED = 2,
+
+ /**
+ * The user is an administrator.
+ */
+ ADMINISTRATOR = 3,
}
diff --git a/src/components/dashboard/user/avatar-setting.tsx b/src/components/dashboard/user/profile/avatar-setting.tsx
similarity index 100%
rename from src/components/dashboard/user/avatar-setting.tsx
rename to src/components/dashboard/user/profile/avatar-setting.tsx
diff --git a/src/components/dashboard/user/email-setting.tsx b/src/components/dashboard/user/profile/email-setting.tsx
similarity index 100%
rename from src/components/dashboard/user/email-setting.tsx
rename to src/components/dashboard/user/profile/email-setting.tsx
diff --git a/src/components/dashboard/user/tier-setting.tsx b/src/components/dashboard/user/profile/tier-setting.tsx
similarity index 97%
rename from src/components/dashboard/user/tier-setting.tsx
rename to src/components/dashboard/user/profile/tier-setting.tsx
index 3359293..ee041c1 100644
--- a/src/components/dashboard/user/tier-setting.tsx
+++ b/src/components/dashboard/user/profile/tier-setting.tsx
@@ -33,7 +33,7 @@ const TierSetting = (): ReactElement => {
{capitalizeWords(user?.tier)}
-
+