Skip to content

Commit b3d274d

Browse files
committed
fix: Change the behavior of the SignIn button for login with provider (#24)
1 parent b8c24b5 commit b3d274d

File tree

15 files changed

+155
-106
lines changed

15 files changed

+155
-106
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AccountRowLabel as AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2-
import { SignInWithAuthjsButton as SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2+
import { SignInButton as SignInButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
33

44
export const importMap = {
55
"payload-authjs/components#AccountRowLabel": AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e,
6-
"payload-authjs/components#SignInWithAuthjsButton": SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e
6+
"payload-authjs/components#SignInButton": SignInButton_06d0cb594d8f6ba2ac35015f930c882e
77
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AccountRowLabel as AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2-
import { SignInWithAuthjsButton as SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2+
import { SignInButton as SignInButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
33

44
export const importMap = {
55
"payload-authjs/components#AccountRowLabel": AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e,
6-
"payload-authjs/components#SignInWithAuthjsButton": SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e
6+
"payload-authjs/components#SignInButton": SignInButton_06d0cb594d8f6ba2ac35015f930c882e
77
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AccountRowLabel as AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2-
import { SignInWithAuthjsButton as SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2+
import { SignInButton as SignInButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
33

44
export const importMap = {
55
"payload-authjs/components#AccountRowLabel": AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e,
6-
"payload-authjs/components#SignInWithAuthjsButton": SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e
6+
"payload-authjs/components#SignInButton": SignInButton_06d0cb594d8f6ba2ac35015f930c882e
77
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { AccountRowLabel as AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2-
import { SignInWithAuthjsButton as SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
2+
import { SignInButton as SignInButton_06d0cb594d8f6ba2ac35015f930c882e } from 'payload-authjs/components'
33
import { default as default_2c1e1c35da30a80d88551f9fcc61be66 } from '../../../payload/components/Greeting'
44

55
export const importMap = {
66
"payload-authjs/components#AccountRowLabel": AccountRowLabel_06d0cb594d8f6ba2ac35015f930c882e,
7-
"payload-authjs/components#SignInWithAuthjsButton": SignInWithAuthjsButton_06d0cb594d8f6ba2ac35015f930c882e,
7+
"payload-authjs/components#SignInButton": SignInButton_06d0cb594d8f6ba2ac35015f930c882e,
88
"/Greeting#default": default_2c1e1c35da30a80d88551f9fcc61be66
99
}

packages/payload-authjs/.swcrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"jsc": {
44
"target": "esnext",
55
"parser": {
6-
"syntax": "typescript"
6+
"syntax": "typescript",
7+
"tsx": true
78
},
89
"transform": {
910
"react": {

packages/payload-authjs/project.json

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@
66
"build": {
77
"executor": "@nx/js:swc",
88
"options": {
9-
"main": "packages/payload-authjs/src/index.ts",
10-
"tsConfig": "packages/payload-authjs/tsconfig.lib.json",
11-
"outputPath": "packages/payload-authjs/dist",
129
"rootDir": "packages/payload-authjs/src",
13-
"stripLeadingPaths": true
10+
"outputPath": "packages/payload-authjs/dist",
11+
"tsConfig": "packages/payload-authjs/tsconfig.lib.json",
12+
"stripLeadingPaths": true,
13+
"main": "packages/payload-authjs/src/index.ts",
14+
"assets": [
15+
{
16+
"input": "packages/payload-authjs/src",
17+
"glob": "**/*.css",
18+
"output": "."
19+
}
20+
]
1421
},
1522
"cache": true
1623
},

packages/payload-authjs/src/authjs/utils/config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
11
import type { NextAuthConfig } from "next-auth";
2+
import type { Provider } from "next-auth/providers";
3+
4+
/**
5+
* Get provider metadata
6+
*/
7+
export const getProviderMetadata = (provider: Provider) => {
8+
const providerOptions = typeof provider === "function" ? provider() : provider;
9+
10+
return {
11+
type: providerOptions.type,
12+
id: (providerOptions.options?.id as string | undefined) ?? providerOptions.id,
13+
name: (providerOptions.options?.name as string | undefined) ?? providerOptions.name,
14+
icon: `https://authjs.dev/img/providers/${providerOptions.id}.svg`,
15+
};
16+
};
217

318
/**
419
* Check if an email provider is available in the authjs config
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.payload-authjs-sign-in-button {
2+
width: 100%;
3+
margin-block: 8px;
4+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"use client";
2+
3+
import { Button } from "@payloadcms/ui";
4+
import { signIn } from "next-auth/react";
5+
import type { ReactNode } from "react";
6+
import type { getProviderMetadata } from "../../authjs/utils/config";
7+
import "./index.css";
8+
9+
export type SignInButtonOptions = {
10+
/**
11+
* Icon to display on the button
12+
*
13+
* @default
14+
* ```tsx
15+
* <img src={provider.iconUrl} alt={`Provider ${provider.name}`} />
16+
* ```
17+
*/
18+
icon?: ReactNode | ((provider: ReturnType<typeof getProviderMetadata>) => ReactNode);
19+
/**
20+
* Text to display on the button
21+
*
22+
* @default
23+
* ```tsx
24+
* <>Sign in with <strong>{provider.name}</strong></>
25+
* ```
26+
*/
27+
text?: ReactNode | ((provider: ReturnType<typeof getProviderMetadata>) => ReactNode);
28+
};
29+
30+
export type SignInButtonProps = {
31+
provider: ReturnType<typeof getProviderMetadata>;
32+
icon?: ReactNode;
33+
text?: ReactNode;
34+
};
35+
36+
/**
37+
* A button to sign in with a Auth.js provider
38+
*/
39+
export const SignInButton = ({
40+
provider,
41+
icon = <img src={provider.icon} alt={`Provider ${provider.name}`} />,
42+
text = (
43+
<>
44+
Sign in with <strong>{provider.name}</strong>
45+
</>
46+
),
47+
}: SignInButtonProps) => {
48+
return (
49+
<Button
50+
className="payload-authjs-sign-in-button"
51+
size="large"
52+
buttonStyle="pill"
53+
icon={icon}
54+
iconPosition="left"
55+
onClick={() => signIn(provider.id)}
56+
>
57+
{text}
58+
</Button>
59+
);
60+
};

packages/payload-authjs/src/components/SignInWithAuthjsButton.tsx

Lines changed: 0 additions & 53 deletions
This file was deleted.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export { AccountRowLabel } from "./AccountRowLabel";
2-
export { SignInWithAuthjsButton } from "./SignInWithAuthjsButton";
2+
export { SignInButton, SignInButton as SignInWithAuthjsButton } from "./SignInButton";

packages/payload-authjs/src/payload/plugin.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { NextAuthConfig } from "next-auth";
22
import type { CollectionSlug, Plugin } from "payload";
3-
import type { SignInWithAuthjsButtonProps } from "../components/SignInWithAuthjsButton";
3+
import { getProviderMetadata } from "../authjs/utils/config";
4+
import type { SignInButtonOptions, SignInButtonProps } from "../components/SignInButton";
45
import { generateUsersCollection } from "./collection";
56

67
export interface AuthjsPluginConfig {
@@ -44,7 +45,7 @@ export interface AuthjsPluginConfig {
4445
* Customize the SignInButton component
4546
* Or set to `false` to disable the SignInButton component
4647
*/
47-
SignInButton?: Omit<SignInWithAuthjsButtonProps, "authjsBasePath"> | false;
48+
SignInButton?: SignInButtonOptions | false;
4849
};
4950
}
5051

@@ -69,19 +70,33 @@ export const authjsPlugin =
6970
...config.admin?.components,
7071
afterLogin: [
7172
...(config.admin?.components?.afterLogin ?? []),
72-
// Add the SignInWithAuthjsButton component to the admin login page (only if the user collection is the admin user collection)
73-
...(incomingConfig.admin?.user === (pluginOptions.userCollectionSlug ?? "users") &&
74-
pluginOptions.components?.SignInButton !== false
75-
? [
76-
{
77-
path: "payload-authjs/components#SignInWithAuthjsButton",
78-
serverProps: {
79-
...pluginOptions.components?.SignInButton,
80-
authjsBasePath: pluginOptions.authjsConfig.basePath,
81-
},
82-
},
83-
]
84-
: []),
73+
// Add the SignInButton component to the admin login page (only if the user collection is the admin user collection)
74+
...(() => {
75+
if (incomingConfig.admin?.user !== (pluginOptions.userCollectionSlug ?? "users")) {
76+
return [];
77+
}
78+
if (pluginOptions.components?.SignInButton === false) {
79+
return [];
80+
}
81+
const signInButtonOptions = pluginOptions.components?.SignInButton;
82+
return pluginOptions.authjsConfig.providers
83+
.map(provider => getProviderMetadata(provider))
84+
.filter(provider => ["oauth", "oidc"].includes(provider.type))
85+
.map(provider => ({
86+
path: "payload-authjs/components#SignInButton",
87+
clientProps: {
88+
icon:
89+
typeof signInButtonOptions?.icon === "function"
90+
? signInButtonOptions.icon(provider)
91+
: signInButtonOptions?.icon,
92+
text:
93+
typeof signInButtonOptions?.text === "function"
94+
? signInButtonOptions.text(provider)
95+
: signInButtonOptions?.text,
96+
provider,
97+
} satisfies SignInButtonProps,
98+
}));
99+
})(),
85100
],
86101
},
87102
};

packages/payload-authjs/tsconfig.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"compilerOptions": {
44
"baseUrl": ".",
55
"moduleResolution": "bundler",
6-
"jsx": "preserve",
7-
"lib": ["DOM", "DOM.Iterable", "ESNext"]
6+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
7+
"jsx": "preserve"
88
},
99
"files": [],
1010
"include": [],

0 commit comments

Comments
 (0)