@sjolystinnovation/app-kit 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +228 -34
- package/package.json +17 -1
- package/src/admin/AdminShell.tsx +53 -0
- package/src/admin/AdminUsersPanel.tsx +276 -0
- package/src/admin/CompanySettingsForm.tsx +122 -0
- package/src/admin/LegalPagesEditor.tsx +131 -0
- package/src/admin/LocaleTabs.tsx +35 -0
- package/src/admin/StatHistoryChart.tsx +99 -0
- package/src/admin/adminUsersPanelStrings.ts +73 -0
- package/src/admin/companySettingsFormStrings.ts +50 -0
- package/src/admin/index.ts +20 -0
- package/src/admin/legalPagesEditorStrings.ts +32 -0
- package/src/admin/statHistoryChartStrings.ts +16 -0
- package/src/api/company.ts +46 -0
- package/src/api/index.ts +4 -0
- package/src/api/revalidateTargets.ts +40 -0
- package/src/legal/LegalPageView.tsx +61 -0
- package/src/legal/index.ts +1 -0
- package/src/next-auth.d.ts +24 -0
- package/src/seo/index.ts +2 -0
- package/src/seo/site.ts +56 -8
- package/src/styles.css +9 -0
- package/src/testing/index.ts +113 -0
- package/src/ui/LoginPage.tsx +54 -0
- package/src/ui/ResetPasswordFlow.tsx +5 -5
- package/src/ui/authClasses.ts +5 -0
- package/src/ui/index.ts +4 -0
- package/src/ui/loginPageStrings.ts +17 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { useRouter } from "next/navigation";
|
|
5
|
+
import { authLinkClassName, authPageClassName, authTitleClassName } from "./authClasses";
|
|
6
|
+
import { CredentialsForm } from "./CredentialsForm";
|
|
7
|
+
import type { CredentialsFormStrings } from "./credentialsFormStrings";
|
|
8
|
+
import { defaultLoginPageStrings, type LoginPageStrings } from "./loginPageStrings";
|
|
9
|
+
import { withDefaults, type TextOverrides } from "./withDefaults";
|
|
10
|
+
|
|
11
|
+
export interface LoginPageProps {
|
|
12
|
+
/** Where a signed-in user goes. */
|
|
13
|
+
redirectTo: string;
|
|
14
|
+
/** The password reset page. */
|
|
15
|
+
resetHref: string;
|
|
16
|
+
/** The sign-up page. Without it the page has no register link. */
|
|
17
|
+
registerHref?: string | undefined;
|
|
18
|
+
strings?: TextOverrides<LoginPageStrings> | undefined;
|
|
19
|
+
/** The form's own text, passed to `CredentialsForm`. */
|
|
20
|
+
formStrings?: TextOverrides<CredentialsFormStrings> | undefined;
|
|
21
|
+
/** Replaces the page's outer spacing, such as when the page sits inside the app's own card. */
|
|
22
|
+
className?: string | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The sign-in page: a title, `CredentialsForm`, and links to reset the password and, when the app has
|
|
27
|
+
* one, to sign up. A sign-in goes to `redirectTo` and refreshes the page's server data.
|
|
28
|
+
*/
|
|
29
|
+
export function LoginPage({ redirectTo, resetHref, registerHref, strings, formStrings, className = authPageClassName }: LoginPageProps) {
|
|
30
|
+
const text = withDefaults(defaultLoginPageStrings, strings);
|
|
31
|
+
const router = useRouter();
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<div className={className}>
|
|
35
|
+
<h1 className={`${authTitleClassName} mb-6`}>{text.title}</h1>
|
|
36
|
+
<CredentialsForm
|
|
37
|
+
strings={formStrings}
|
|
38
|
+
onSignedIn={() => {
|
|
39
|
+
router.push(redirectTo);
|
|
40
|
+
router.refresh();
|
|
41
|
+
}}
|
|
42
|
+
/>
|
|
43
|
+
<p className="mt-6 text-sm text-auth-text">
|
|
44
|
+
<Link href={resetHref} className={authLinkClassName}>{text.forgotPassword}</Link>
|
|
45
|
+
</p>
|
|
46
|
+
{registerHref && (
|
|
47
|
+
<p className="mt-2 text-sm text-auth-text">
|
|
48
|
+
{text.registerPrompt && <>{text.registerPrompt} </>}
|
|
49
|
+
<Link href={registerHref} className={authLinkClassName}>{text.register}</Link>
|
|
50
|
+
</p>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -4,6 +4,7 @@ import Link from "next/link";
|
|
|
4
4
|
import { useState, type FormEvent } from "react";
|
|
5
5
|
import { passwordProblems, type PasswordStrings } from "../validation/passwordRules";
|
|
6
6
|
import { Alert } from "./Alert";
|
|
7
|
+
import { authLinkClassName, authPageClassName, authTitleClassName } from "./authClasses";
|
|
7
8
|
import { PasswordInput } from "./PasswordInput";
|
|
8
9
|
import { defaultResetPasswordFlowStrings, type ResetPasswordFlowStrings } from "./resetPasswordFlowStrings";
|
|
9
10
|
import { TextInput } from "./TextInput";
|
|
@@ -28,7 +29,6 @@ export interface ResetPasswordFlowProps {
|
|
|
28
29
|
|
|
29
30
|
const button =
|
|
30
31
|
"w-full rounded-button bg-button-primary-bg text-button-primary-text font-semibold py-2.5 hover:brightness-95 disabled:opacity-60 transition";
|
|
31
|
-
const link = "font-auth-link text-auth-link hover:text-auth-link-hover transition-colors";
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Password reset in two steps: the email asks for a code, then the code and a new password set it. The
|
|
@@ -42,7 +42,7 @@ export function ResetPasswordFlow({
|
|
|
42
42
|
initialEmail = "",
|
|
43
43
|
initialCode = "",
|
|
44
44
|
strings,
|
|
45
|
-
className =
|
|
45
|
+
className = authPageClassName,
|
|
46
46
|
passwordStrings,
|
|
47
47
|
}: ResetPasswordFlowProps) {
|
|
48
48
|
const text = withDefaults(defaultResetPasswordFlowStrings, strings);
|
|
@@ -92,16 +92,16 @@ export function ResetPasswordFlow({
|
|
|
92
92
|
|
|
93
93
|
return (
|
|
94
94
|
<div className={className}>
|
|
95
|
-
<h1 className=
|
|
95
|
+
<h1 className={`${authTitleClassName} mb-1`}>{text.title}</h1>
|
|
96
96
|
<p className="text-sm text-auth-text mb-6">
|
|
97
97
|
{text.signInPrompt && <>{text.signInPrompt} </>}
|
|
98
|
-
<Link href={loginHref} className={
|
|
98
|
+
<Link href={loginHref} className={authLinkClassName}>{text.signIn}</Link>
|
|
99
99
|
</p>
|
|
100
100
|
|
|
101
101
|
{done !== null ? (
|
|
102
102
|
<Alert variant="success">
|
|
103
103
|
{done}
|
|
104
|
-
<Link href={loginHref} className={`block mt-3 ${
|
|
104
|
+
<Link href={loginHref} className={`block mt-3 ${authLinkClassName}`}>{text.backToSignIn}</Link>
|
|
105
105
|
</Alert>
|
|
106
106
|
) : step === 1 ? (
|
|
107
107
|
<form onSubmit={sendCode} className="space-y-4">
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The classes the sign-in and password reset pages share, drawn from the auth and button tokens.
|
|
2
|
+
|
|
3
|
+
export const authPageClassName = "max-w-md mx-auto px-4 py-16";
|
|
4
|
+
export const authTitleClassName = "text-auth-title font-auth-title text-auth-heading";
|
|
5
|
+
export const authLinkClassName = "font-auth-link text-auth-link hover:text-auth-link-hover transition-colors";
|
package/src/ui/index.ts
CHANGED
|
@@ -8,6 +8,10 @@ export { SignInRejected, defaultCredentialsFormStrings } from "./credentialsForm
|
|
|
8
8
|
export type { CredentialsFormStrings } from "./credentialsFormStrings";
|
|
9
9
|
export { ErrorState, defaultErrorStateStrings } from "./ErrorState";
|
|
10
10
|
export type { ErrorStateProps, ErrorStateStrings } from "./ErrorState";
|
|
11
|
+
export { LoginPage } from "./LoginPage";
|
|
12
|
+
export type { LoginPageProps } from "./LoginPage";
|
|
13
|
+
export { defaultLoginPageStrings } from "./loginPageStrings";
|
|
14
|
+
export type { LoginPageStrings } from "./loginPageStrings";
|
|
11
15
|
export { NotFoundState, defaultNotFoundStrings } from "./NotFoundState";
|
|
12
16
|
export type { NotFoundStateProps, NotFoundStrings } from "./NotFoundState";
|
|
13
17
|
export { PasswordInput } from "./PasswordInput";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Plain values, with no "use client", so a server component can import them.
|
|
2
|
+
|
|
3
|
+
/** The sign-in page's text around the form. Pass the app's own language. The defaults are English. */
|
|
4
|
+
export interface LoginPageStrings {
|
|
5
|
+
title: string;
|
|
6
|
+
forgotPassword: string;
|
|
7
|
+
/** Shown before the register link, such as "No account?". Null leaves it out. */
|
|
8
|
+
registerPrompt: string | null;
|
|
9
|
+
register: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const defaultLoginPageStrings: LoginPageStrings = {
|
|
13
|
+
title: "Sign in",
|
|
14
|
+
forgotPassword: "Forgot your password?",
|
|
15
|
+
registerPrompt: "No account?",
|
|
16
|
+
register: "Create one",
|
|
17
|
+
};
|