mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Patching bug on portabase.config.ts about social providers.
This commit is contained in:
@@ -24,18 +24,16 @@ export default async function SignInPage() {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<LoginForm />
|
<LoginForm/>
|
||||||
|
|
||||||
{SUPPORTED_PROVIDERS.filter((p) => !p.isManual).length > 0 && (
|
{SUPPORTED_PROVIDERS.filter((p) => !p.isManual && p.isActive).length > 0 && (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<div className="relative my-4 flex items-center justify-center overflow-hidden">
|
<div className="relative my-4 flex items-center justify-center overflow-hidden">
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<div className="px-2 text-center text-sm">OR</div>
|
<div className="px-2 text-center text-sm">OR</div>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
</div>
|
</div>
|
||||||
|
<SocialAuthButtons providers={SUPPORTED_PROVIDERS}/>
|
||||||
<SocialAuthButtons />
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -50,7 +48,5 @@ export default async function SignInPage() {
|
|||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -1,9 +1,9 @@
|
|||||||
import {Chrome, KeyRound, LucideIcon} from "lucide-react";
|
|
||||||
|
|
||||||
|
|
||||||
export interface AuthProviderConfig {
|
export interface AuthProviderConfig {
|
||||||
id: "google" | "github" | "credential";
|
id: "google" | "github" | "credential";
|
||||||
icon: LucideIcon;
|
isActive: boolean;
|
||||||
|
icon: string;
|
||||||
isManual?: boolean;
|
isManual?: boolean;
|
||||||
credentials?: {
|
credentials?: {
|
||||||
clientId: string;
|
clientId: string;
|
||||||
@@ -80,7 +80,8 @@ export const PORTABASE_DEFAULT_SETTINGS = {
|
|||||||
export const SUPPORTED_PROVIDERS: AuthProviderConfig[] = [
|
export const SUPPORTED_PROVIDERS: AuthProviderConfig[] = [
|
||||||
{
|
{
|
||||||
id: "google",
|
id: "google",
|
||||||
icon: Chrome,
|
icon: "hugeicons:chrome",
|
||||||
|
isActive: Boolean(process.env.AUTH_GOOGLE_METHOD),
|
||||||
// isManual: true,
|
// isManual: true,
|
||||||
credentials: {
|
credentials: {
|
||||||
clientId: process.env.GOOGLE_CLIENT_ID || "",
|
clientId: process.env.GOOGLE_CLIENT_ID || "",
|
||||||
@@ -100,7 +101,8 @@ export const SUPPORTED_PROVIDERS: AuthProviderConfig[] = [
|
|||||||
},*/
|
},*/
|
||||||
{
|
{
|
||||||
id: "credential",
|
id: "credential",
|
||||||
icon: KeyRound,
|
isActive: true,
|
||||||
|
icon: "proicons:key",
|
||||||
isManual: true,
|
isManual: true,
|
||||||
credentials: {
|
credentials: {
|
||||||
clientId: "",
|
clientId: "",
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { authClient } from "@/lib/auth/auth-client";
|
import { authClient } from "@/lib/auth/auth-client";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import {SUPPORTED_PROVIDERS} from "../../../../portabase.config";
|
import {AuthProviderConfig} from "../../../../portabase.config";
|
||||||
|
import {Icon} from "@iconify/react";
|
||||||
|
|
||||||
|
export function SocialAuthButtons({ providers }: { providers: AuthProviderConfig[] }) {
|
||||||
|
const socialProviders = providers.filter(p => p.isActive && !p.isManual);
|
||||||
|
|
||||||
export function SocialAuthButtons() {
|
|
||||||
const [isLoading, setIsLoading] = useState<string | null>(null);
|
const [isLoading, setIsLoading] = useState<string | null>(null);
|
||||||
|
|
||||||
const handleSocialSignIn = async (providerId: string) => {
|
const handleSocialSignIn = async (providerId: string) => {
|
||||||
@@ -30,16 +33,15 @@ export function SocialAuthButtons() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const socialProviders = SUPPORTED_PROVIDERS.filter((p) => !p.isManual);
|
|
||||||
|
|
||||||
if (socialProviders.length === 0) return null;
|
if (socialProviders.length === 0) return null;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-2 w-full">
|
<div className="flex flex-col gap-2 w-full">
|
||||||
{socialProviders.map((provider) => (
|
{socialProviders.map((provider) => (
|
||||||
<Button key={provider.id} variant="outline" className="w-full gap-2" onClick={() => handleSocialSignIn(provider.id)} disabled={!!isLoading}>
|
<Button key={provider.id} variant="outline" className="w-full gap-2" onClick={() => handleSocialSignIn(provider.id)} disabled={!!isLoading}>
|
||||||
{isLoading === provider.id ? <Loader2 className="h-4 w-4 animate-spin" /> : <provider.icon className="h-4 w-4" />}
|
{isLoading === provider.id ? <Loader2 className="h-4 w-4 animate-spin" /> :
|
||||||
|
<Icon icon={provider.icon} className="h-4 w-4"/>
|
||||||
|
}
|
||||||
<span>{PROVIDERS_TEXT[provider.id].title}</span>
|
<span>{PROVIDERS_TEXT[provider.id].title}</span>
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {currentUser} from "@/lib/auth/current-user";
|
import {currentUser} from "@/lib/auth/current-user";
|
||||||
import {getAccounts, getSession, getSessions} from "@/lib/auth/auth";
|
import {getAccounts, getSession, getSessions} from "@/lib/auth/auth";
|
||||||
import {LoggedInButtonClient} from "./logged-in-button";
|
import {LoggedInButtonClient} from "./logged-in-button";
|
||||||
|
import {SUPPORTED_PROVIDERS} from "../../../../../../portabase.config";
|
||||||
|
|
||||||
export const LoggedInButton = async () => {
|
export const LoggedInButton = async () => {
|
||||||
const user = await currentUser();
|
const user = await currentUser();
|
||||||
@@ -18,6 +19,7 @@ export const LoggedInButton = async () => {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
currentSession={currentSession.session}
|
currentSession={currentSession.session}
|
||||||
accounts={accounts}
|
accounts={accounts}
|
||||||
|
providers={SUPPORTED_PROVIDERS.filter((p) => p.isActive)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,46 +1,3 @@
|
|||||||
// import { ChevronUp } from "lucide-react";
|
|
||||||
//
|
|
||||||
// import {Avatar, AvatarFallback, AvatarImage} from "@/components/ui/avatar";
|
|
||||||
// import { currentUser } from "@/lib/auth/current-user";
|
|
||||||
// import { SidebarMenuButton } from "@/components/ui/sidebar";
|
|
||||||
// import { getAccounts, getSession, getSessions } from "@/lib/auth/auth";
|
|
||||||
// import {LoggedInDropdown} from "@/components/wrappers/dashboard/common/logged-in/logged-in-dropdown";
|
|
||||||
//
|
|
||||||
// export const LoggedInButton = async () => {
|
|
||||||
// const user = await currentUser();
|
|
||||||
// const sessions = await getSessions();
|
|
||||||
// const currentSession = await getSession();
|
|
||||||
// const accounts = await getAccounts();
|
|
||||||
//
|
|
||||||
// if (!user) return null;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// <LoggedInDropdown
|
|
||||||
// // @ts-ignore
|
|
||||||
// user={user}
|
|
||||||
// // @ts-ignore
|
|
||||||
// sessions={sessions}
|
|
||||||
// // @ts-ignore
|
|
||||||
// currentSession={currentSession.session}
|
|
||||||
// // @ts-ignore
|
|
||||||
// accounts={accounts}
|
|
||||||
// >
|
|
||||||
// <SidebarMenuButton>
|
|
||||||
//
|
|
||||||
// <Avatar className="size-6">
|
|
||||||
// <AvatarFallback>{user?.name[0].toUpperCase()}</AvatarFallback>
|
|
||||||
// {user?.image ? <AvatarImage src={user?.image} alt={`${user.name ?? "-"}'s profile picture`} /> : null}
|
|
||||||
// </Avatar>
|
|
||||||
//
|
|
||||||
// <span className="first-letter:capitalize">{user?.name}</span>
|
|
||||||
// <ChevronUp className="ml-auto" />
|
|
||||||
// </SidebarMenuButton>
|
|
||||||
// </LoggedInDropdown>
|
|
||||||
// </>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import {ChevronUp} from "lucide-react";
|
import {ChevronUp} from "lucide-react";
|
||||||
@@ -48,15 +5,23 @@ import {Avatar, AvatarFallback, AvatarImage} from "@/components/ui/avatar";
|
|||||||
import {SidebarMenuButton} from "@/components/ui/sidebar";
|
import {SidebarMenuButton} from "@/components/ui/sidebar";
|
||||||
import {LoggedInDropdown} from "./logged-in-dropdown";
|
import {LoggedInDropdown} from "./logged-in-dropdown";
|
||||||
import {Account, Session, User} from "better-auth";
|
import {Account, Session, User} from "better-auth";
|
||||||
|
import {AuthProviderConfig} from "../../../../../../portabase.config";
|
||||||
|
|
||||||
type LoggedInButtonClientProps = {
|
type LoggedInButtonClientProps = {
|
||||||
user: User;
|
user: User,
|
||||||
sessions: Session[];
|
sessions: Session[],
|
||||||
currentSession: Session;
|
currentSession: Session,
|
||||||
accounts: Account[];
|
accounts: Account[],
|
||||||
|
providers: AuthProviderConfig[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LoggedInButtonClient = ({user, sessions, currentSession, accounts}: LoggedInButtonClientProps) => {
|
export const LoggedInButtonClient = ({
|
||||||
|
user,
|
||||||
|
sessions,
|
||||||
|
currentSession,
|
||||||
|
accounts,
|
||||||
|
providers
|
||||||
|
}: LoggedInButtonClientProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoggedInDropdown
|
<LoggedInDropdown
|
||||||
@@ -68,6 +33,7 @@ export const LoggedInButtonClient = ({user, sessions, currentSession, accounts}:
|
|||||||
currentSession={currentSession}
|
currentSession={currentSession}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
accounts={accounts}
|
accounts={accounts}
|
||||||
|
providers={providers}
|
||||||
>
|
>
|
||||||
<SidebarMenuButton type="button">
|
<SidebarMenuButton type="button">
|
||||||
<Avatar className="size-6">
|
<Avatar className="size-6">
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
|
|||||||
import { signOut } from "@/lib/auth/auth-client";
|
import { signOut } from "@/lib/auth/auth-client";
|
||||||
import {ProfileModal} from "@/components/wrappers/dashboard/common/profile/profile-modal";
|
import {ProfileModal} from "@/components/wrappers/dashboard/common/profile/profile-modal";
|
||||||
import {Account, Session, User} from "@/db/schema/02_user";
|
import {Account, Session, User} from "@/db/schema/02_user";
|
||||||
|
import {AuthProviderConfig} from "../../../../../../portabase.config";
|
||||||
|
|
||||||
export type LoggedInDropdownProps = PropsWithChildren<{
|
export type LoggedInDropdownProps = PropsWithChildren<{
|
||||||
user: User;
|
user: User;
|
||||||
@@ -14,9 +15,11 @@ export type LoggedInDropdownProps = PropsWithChildren<{
|
|||||||
currentSession: Session;
|
currentSession: Session;
|
||||||
accounts: Account[];
|
accounts: Account[];
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
providers: AuthProviderConfig[]
|
||||||
|
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export const LoggedInDropdown = ({ user, sessions, currentSession, accounts, children }: LoggedInDropdownProps) => {
|
export const LoggedInDropdown = ({ user, sessions, currentSession, accounts, children, providers }: LoggedInDropdownProps) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
@@ -29,6 +32,7 @@ export const LoggedInDropdown = ({ user, sessions, currentSession, accounts, chi
|
|||||||
accounts={accounts}
|
accounts={accounts}
|
||||||
open={isModalOpen}
|
open={isModalOpen}
|
||||||
onOpenChange={setIsModalOpen}
|
onOpenChange={setIsModalOpen}
|
||||||
|
providers={providers}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {ProfileAccount} from "@/components/wrappers/dashboard/profile/profile-ac
|
|||||||
import {ProfileAppearance} from "@/components/wrappers/dashboard/profile/profile-apperance";
|
import {ProfileAppearance} from "@/components/wrappers/dashboard/profile/profile-apperance";
|
||||||
import {ProfileSecurity} from "@/components/wrappers/dashboard/profile/profile-security";
|
import {ProfileSecurity} from "@/components/wrappers/dashboard/profile/profile-security";
|
||||||
import {ProfileGeneral} from "@/components/wrappers/dashboard/profile/profile-general";
|
import {ProfileGeneral} from "@/components/wrappers/dashboard/profile/profile-general";
|
||||||
|
import {AuthProviderConfig} from "../../../../../../portabase.config";
|
||||||
|
|
||||||
type ProfileModalProps = {
|
type ProfileModalProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -18,9 +19,11 @@ type ProfileModalProps = {
|
|||||||
currentSession: Session;
|
currentSession: Session;
|
||||||
accounts: Account[];
|
accounts: Account[];
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
|
providers: AuthProviderConfig[]
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ProfileModal = ({ user, sessions, currentSession, accounts, open, onOpenChange }: ProfileModalProps) => {
|
export const ProfileModal = ({ user, sessions, currentSession, accounts, open, onOpenChange, providers }: ProfileModalProps) => {
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent className="w-[95vw] h-[90vh] max-w-md lg:max-w-[1000px] lg:h-[800px] p-0 overflow-hidden flex flex-col outline-none gap-0 rounded-xl bg-background">
|
<DialogContent className="w-[95vw] h-[90vh] max-w-md lg:max-w-[1000px] lg:h-[800px] p-0 overflow-hidden flex flex-col outline-none gap-0 rounded-xl bg-background">
|
||||||
@@ -46,7 +49,7 @@ export const ProfileModal = ({ user, sessions, currentSession, accounts, open, o
|
|||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="providers" className="mt-0 h-full p-6 lg:p-10 outline-none focus-visible:ring-0">
|
<TabsContent value="providers" className="mt-0 h-full p-6 lg:p-10 outline-none focus-visible:ring-0">
|
||||||
<ProfileProviders accounts={accounts} />
|
<ProfileProviders accounts={accounts} providers={providers} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="account" className="mt-0 h-full p-6 lg:p-10 outline-none focus-visible:ring-0">
|
<TabsContent value="account" className="mt-0 h-full p-6 lg:p-10 outline-none focus-visible:ring-0">
|
||||||
|
|||||||
@@ -12,13 +12,16 @@ import {useRouter} from "next/navigation";
|
|||||||
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
|
import {Tooltip, TooltipContent, TooltipProvider, TooltipTrigger} from "@/components/ui/tooltip";
|
||||||
import {Alert, AlertDescription} from "@/components/ui/alert";
|
import {Alert, AlertDescription} from "@/components/ui/alert";
|
||||||
import {SetPasswordProfileProviderModal} from "./modal/set-password-modal";
|
import {SetPasswordProfileProviderModal} from "./modal/set-password-modal";
|
||||||
import {SUPPORTED_PROVIDERS} from "../../../../../portabase.config";
|
import {AuthProviderConfig} from "../../../../../portabase.config";
|
||||||
|
import {Icon} from "@iconify/react";
|
||||||
|
|
||||||
interface ProfileProviderProps {
|
interface ProfileProviderProps {
|
||||||
accounts: Account[];
|
accounts: Account[];
|
||||||
|
providers: AuthProviderConfig[]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProfileProviders({accounts}: ProfileProviderProps) {
|
export function ProfileProviders({accounts, providers}: ProfileProviderProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const totalConnected = accounts.length;
|
const totalConnected = accounts.length;
|
||||||
const [loadingProvider, setLoadingProvider] = useState<string | null>(null);
|
const [loadingProvider, setLoadingProvider] = useState<string | null>(null);
|
||||||
@@ -70,7 +73,7 @@ export function ProfileProviders({accounts}: ProfileProviderProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
{SUPPORTED_PROVIDERS.map((provider) => {
|
{providers.map((provider) => {
|
||||||
const linkedAccount = accounts.find((acc) => acc.providerId === provider.id);
|
const linkedAccount = accounts.find((acc) => acc.providerId === provider.id);
|
||||||
const isConnected = !!linkedAccount;
|
const isConnected = !!linkedAccount;
|
||||||
// const canUnlink = totalConnected > 1 || (totalConnected === 1 && !provider.isManual);
|
// const canUnlink = totalConnected > 1 || (totalConnected === 1 && !provider.isManual);
|
||||||
@@ -83,7 +86,7 @@ export function ProfileProviders({accounts}: ProfileProviderProps) {
|
|||||||
className="flex items-center justify-between p-4 border rounded-lg hover:bg-muted/30 transition-colors">
|
className="flex items-center justify-between p-4 border rounded-lg hover:bg-muted/30 transition-colors">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div className="w-10 h-10 rounded-full bg-muted flex items-center justify-center">
|
<div className="w-10 h-10 rounded-full bg-muted flex items-center justify-center">
|
||||||
<provider.icon className="w-5 h-5"/>
|
<Icon icon={provider.icon} className="w-5 h-5"/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-0.5">
|
<div className="space-y-0.5">
|
||||||
<div className="font-medium flex items-center gap-2">
|
<div className="font-medium flex items-center gap-2">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {count, eq} from "drizzle-orm";
|
|||||||
import {MemberWithUser, OrganizationWithMembersAndUsers} from "@/db/schema/03_organization";
|
import {MemberWithUser, OrganizationWithMembersAndUsers} from "@/db/schema/03_organization";
|
||||||
import {sendEmail} from "@/lib/email/email-helper";
|
import {sendEmail} from "@/lib/email/email-helper";
|
||||||
import {render} from "@react-email/render";
|
import {render} from "@react-email/render";
|
||||||
import {SUPPORTED_PROVIDERS} from "../../../portabase.config";
|
import {AuthProviderConfig, SUPPORTED_PROVIDERS} from "../../../portabase.config";
|
||||||
import {withUpdatedAt} from "@/db/utils";
|
import {withUpdatedAt} from "@/db/utils";
|
||||||
import EmailVerification from "@/components/emails/auth/email-verification";
|
import EmailVerification from "@/components/emails/auth/email-verification";
|
||||||
import EmailForgotPassword from "@/components/emails/auth/email-forgot-password";
|
import EmailForgotPassword from "@/components/emails/auth/email-forgot-password";
|
||||||
@@ -80,6 +80,7 @@ export const auth = betterAuth({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
socialProviders: SUPPORTED_PROVIDERS.reduce((acc: any, provider: any) => {
|
socialProviders: SUPPORTED_PROVIDERS.reduce((acc: any, provider: any) => {
|
||||||
|
if (!provider.isActive) return acc;
|
||||||
if (provider.id === "credential") return acc;
|
if (provider.id === "credential") return acc;
|
||||||
if (provider.id === "google") {
|
if (provider.id === "google") {
|
||||||
acc.google = {
|
acc.google = {
|
||||||
|
|||||||
Reference in New Issue
Block a user