Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add login to app #634

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,743 changes: 413 additions & 1,330 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"mailchimp-api-v3": "^1.15.0",
"marked": "^4.0.18",
"next": "12.2.2",
"next-auth": "^4.24.10",
"next-pwa": "^5.5.4",
"next-react-svg": "^1.1.3",
"next-seo": "^5.5.0",
Expand All @@ -59,6 +60,7 @@
"@types/google.maps": "^3.58.1",
"@types/jsonwebtoken": "^8.5.8",
"@types/marked": "^4.0.3",
"@types/next-auth": "^3.15.0",
"@types/node": "^18.0.0",
"@types/react": "18.0.0",
"@types/react-dom": "18.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/social-share/layout-01/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const SocialShare = () => {
<div
className={clsx(
"tw-absolute tw-bottom-full tw-left-1/2 -tw-translate-x-1/2 -tw-translate-y-2.5 tw-w-auto tw-whitespace-nowrap tw-px-1 tw-bg-white tw-rounded tw-shadow-3sm tw-shadow-black/[.06]",
"tw-drop-shadow-[0_2px_20px_rgba(0,0,0,0.06)] tw-z-10 tw-select-none tw-transition-all tw-duration-300 tw-ease-[cubic-bezier(.71,1.7,.77,1.24)] tw-invisible tw-opacity-0",
"tw-drop-shadow-[0_2px_20px_rgba(0,0,0,0.06)] tw-z-10 tw-select-none tw-transition-all tw-duration-300 tw-ease-&lsqb;cubic-bezier(.71,1.7,.77,1.24)&rsqb; tw-invisible tw-opacity-0",
"before:tw-absolute before:tw-content-[''] before:tw-top-full before:tw-left-1/2 before:-tw-translate-x-1/2 before:tw-border-t-8 before:tw-border-t-white before:tw-border-x-[9px] before:tw-border-x-transparent before:tw-invisible before:tw-opacity-0",
"after:tw-absolute after:tw-content-[''] after:tw-left-0 after:-tw-bottom-6 after:tw-w-full after:tw-h-7",
"group-hover:tw-visible group-hover:tw-opacity-100 group-hover:-tw-translate-x-1/2 group-hover:-tw-translate-y-5 group-hover:before:tw-visible group-hover:before:tw-opacity-100"
Expand Down
4 changes: 2 additions & 2 deletions src/components/social-share/layout-01/social-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ const SocialLink = ({ children, href, label, onClick }: TProps) => {
<a
className={clsx(
"tw-relative tw-inline-block tw-text-base tw-py-2.5 tw-px-3.8 tw-text-gray-400",
"before:tw-absolute before:tw-content-[''] before:tw-border-[7px] before:tw-border-transparent before:tw-border-t-primary before:tw-bottom-full before:left-[calc(50%_-_7px) before:tw-transition-all before:tw-duration-300 before:tw-ease-[cubic-bezier(.71,1.7,.77,1.24)] before:tw-pointer-events-none before:tw-z-20 before:tw-mb-[-13px] before:tw-invisible before:tw-opacity-0",
"after:tw-absolute after:tw-content-[attr(aria-label)] after:tw-bg-primary after:tw-text-white after:tw-py-2 after:tw-px-2.5 after:tw-leading-none after:tw-whitespace-nowrap after:tw-rounded after:tw-shadow-xs after:tw-shadow-black/30 after:tw-bottom-full after:tw-left-1/2 after:-tw-translate-x-1/2 after:tw-transition-all after:tw-duration-300 after:tw-ease-[cubic-bezier(.71,1.7,.77,1.24)] after:tw-pointer-events-none after:tw-z-10 after:tw-invisible after:tw-opacity-0",
"before:tw-absolute before:tw-content-[''] before:tw-border-[7px] before:tw-border-transparent before:tw-border-t-primary before:tw-bottom-full before:left-[calc(50%_-_7px) before:tw-transition-all before:tw-duration-300 before:tw-ease-&lsqb;cubic-bezier(.71,1.7,.77,1.24)&rsqb; before:tw-pointer-events-none before:tw-z-20 before:tw-mb-[-13px] before:tw-invisible before:tw-opacity-0",
"after:tw-absolute after:tw-content-[attr(aria-label)] after:tw-bg-primary after:tw-text-white after:tw-py-2 after:tw-px-2.5 after:tw-leading-none after:tw-whitespace-nowrap after:tw-rounded after:tw-shadow-xs after:tw-shadow-black/30 after:tw-bottom-full after:tw-left-1/2 after:-tw-translate-x-1/2 after:tw-transition-all after:tw-duration-300 after:tw-ease-&lsqb;cubic-bezier(.71,1.7,.77,1.24)&rsqb; after:tw-pointer-events-none after:tw-z-10 after:tw-invisible after:tw-opacity-0",
"hover:before:tw-visible hover:before:tw-opacity-100 hover:before:tw-delay-100 hover:before:-tw-translate-y-2 hover:after:tw-visible hover:after:tw-opacity-100 hover:after:tw-delay-100 hover:after:-tw-translate-y-2"
)}
href={href}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/social/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const Social = ({
return null;
});
const flyoutClass =
"tw-absolute tw-bottom-full tw-right-0 -tw-translate-y-2.5 tw-w-auto tw-whitespace-nowrap tw-px-1 tw-bg-white tw-rounded tw-shadow-3sm tw-shadow-black/[.06] tw-drop-shadow-[0_2px_20px_rgba(0,0,0,0.06)] tw-z-10 tw-select-none tw-transition-all tw-duration-300 tw-ease-[cubic-bezier(.71,1.7,.77,1.24)] tw-invisible tw-opacity-0";
"tw-absolute tw-bottom-full tw-right-0 -tw-translate-y-2.5 tw-w-auto tw-whitespace-nowrap tw-px-1 tw-bg-white tw-rounded tw-shadow-3sm tw-shadow-black/[.06] tw-drop-shadow-[0_2px_20px_rgba(0,0,0,0.06)] tw-z-10 tw-select-none tw-transition-all tw-duration-300 tw-ease-&lsqb;cubic-bezier(.71,1.7,.77,1.24)&rsqb; tw-invisible tw-opacity-0";
const flyoutBeforeClass =
"before:tw-absolute before:tw-content-[''] before:tw-top-full before:tw-right-5 before:tw-border-t-8 before:tw-border-t-white before:tw-border-x-[9px] before:tw-border-x-transparent before:tw-invisible before:tw-opacity-0";
const flyoutAfterClass =
Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/social/social-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ const SocialLink = ({

// Toopltip
const tooltipBeforeClass =
"before:tw-absolute before:tw-content-[''] before:tw-border-[7px] before:tw-border-transparent before:tw-border-t-primary before:tw-bottom-full before:left-[calc(50%_-_7px) before:tw-transition-all before:tw-duration-300 before:tw-ease-[cubic-bezier(.71,1.7,.77,1.24)] before:tw-pointer-events-none before:tw-z-20 before:tw-mb-[-13px] before:tw-invisible before:tw-opacity-0";
"before:tw-absolute before:tw-content-[''] before:tw-border-[7px] before:tw-border-transparent before:tw-border-t-primary before:tw-bottom-full before:left-[calc(50%_-_7px) before:tw-transition-all before:tw-duration-300 before:tw-ease-&lsqb;cubic-bezier(.71,1.7,.77,1.24)&rsqb; before:tw-pointer-events-none before:tw-z-20 before:tw-mb-[-13px] before:tw-invisible before:tw-opacity-0";
const tooltipAfterClass =
"after:tw-absolute after:tw-content-[attr(aria-label)] after:tw-bg-primary after:tw-text-white after:tw-py-2 after:tw-px-2.5 after:tw-leading-none after:tw-whitespace-nowrap after:tw-rounded after:tw-shadow-xs after:tw-shadow-black/30 after:tw-bottom-full after:tw-left-1/2 after:-tw-translate-x-1/2 after:tw-transition-all after:tw-duration-300 after:tw-ease-[cubic-bezier(.71,1.7,.77,1.24)] after:tw-pointer-events-none after:tw-z-10 after:tw-invisible after:tw-opacity-0";
"after:tw-absolute after:tw-content-[attr(aria-label)] after:tw-bg-primary after:tw-text-white after:tw-py-2 after:tw-px-2.5 after:tw-leading-none after:tw-whitespace-nowrap after:tw-rounded after:tw-shadow-xs after:tw-shadow-black/30 after:tw-bottom-full after:tw-left-1/2 after:-tw-translate-x-1/2 after:tw-transition-all after:tw-duration-300 after:tw-ease-&lsqb;cubic-bezier(.71,1.7,.77,1.24)&rsqb; after:tw-pointer-events-none after:tw-z-10 after:tw-invisible after:tw-opacity-0";
const tooltipHoverClass =
"hover:before:tw-visible hover:before:tw-opacity-100 hover:before:tw-delay-100 hover:before:-tw-translate-y-2 hover:after:tw-visible hover:after:tw-opacity-100 hover:after:tw-delay-100 hover:after:-tw-translate-y-2";

Expand Down
31 changes: 19 additions & 12 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ElementType, useEffect } from "react";
import { useRouter } from "next/router";
import type { AppProps } from "next/app";
import { SessionProvider } from "next-auth/react"; // Import SessionProvider
import type { Session } from "next-auth"; // Import Session type
import type { AppProps, NextPage } from "next"; // Import NextPage
import SEO from "@components/seo/deafult-seo";
import FallbackLayout from "@layout/fallback";
import "@assets/css/font-awesome-pro.min.css";
Expand All @@ -13,9 +15,13 @@ import "@assets/css/globals.css";
import { UIProvider } from "../contexts/ui-context";
import { UserProvider } from "../contexts/user-context";

interface CustomAppProps extends Omit<AppProps, "Component"> {
Component: AppProps["Component"] & { Layout: ElementType };
// Extend AppProps with support for a Layout property
interface CustomAppProps extends AppProps {
Component: NextPage & {
Layout?: ElementType; // Optional Layout property
};
pageProps: {
session?: Session | null; // Explicitly type session
[key: string]: unknown;
};
}
Expand All @@ -27,7 +33,6 @@ const MyApp = ({ Component, pageProps }: CustomAppProps) => {
typeof pageProps.layout === "object" ? pageProps.layout : {};

useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
document.activeElement instanceof HTMLElement &&
document.activeElement.blur();
}, [router]);
Expand All @@ -37,14 +42,16 @@ const MyApp = ({ Component, pageProps }: CustomAppProps) => {
});

return (
<UIProvider>
<UserProvider>
<Layout {...layoutProps}>
<SEO />
<Component {...pageProps} />
</Layout>
</UserProvider>
</UIProvider>
<SessionProvider session={pageProps.session as Session | null}>
<UIProvider>
<UserProvider>
<Layout {...layoutProps}>
<SEO />
<Component {...pageProps} />
</Layout>
</UserProvider>
</UIProvider>
</SessionProvider>
);
};

Expand Down
78 changes: 78 additions & 0 deletions src/pages/api/auth/[...nextauth].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import NextAuth from "next-auth";
import GitHubProvider from "next-auth/providers/github";

export const authOptions = {
providers: [
GitHubProvider({
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
authorization: {
params: {
scope: "read:org",
},
},
}),
],
callbacks: {
async signIn({ account }) {
if (account.provider === "github") {
try {
const res = await fetch(
"https://api.github.com/user/orgs",
{
headers: {
Authorization: `Bearer ${account.access_token}`,
},
}
);

if (!res.ok) {
console.error(
`GitHub API returned an error: ${res.status} ${res.statusText}`
);
return false;
}

const orgs = await res.json();

if (!Array.isArray(orgs)) {
console.error("Unexpected GitHub API response:", orgs);
return false;
}

const isMember = orgs.some(
(org) => org.login === process.env.GITHUB_ORG
);

if (!isMember) {
console.log(
`Access denied: Not a member of the organization ${process.env.GITHUB_ORG}`
);
return false;
}
} catch (error) {
console.error(
"Error fetching GitHub organizations:",
error
);
return false;
}
}

return true; // Allow login
},
async session({ session, token }) {
session.user.id = token.id;
return session;
},
async jwt({ token, user, account }) {
if (account) {
token.id = user.id;
}
return token;
},
},
secret: process.env.NEXTAUTH_SECRET,
};

export default NextAuth(authOptions);
36 changes: 25 additions & 11 deletions src/pages/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,31 @@ import { useRouter } from "next/router";
import PageSeo from "@components/seo/page-seo";
import Layout from "@layout/layout-01";
import Breadcrumb from "@components/breadcrumb";
import LoginForm from "@components/forms/login-form";
import Spinner from "@ui/spinner";
import { useUser } from "@contexts/user-context";
import { useMount } from "@hooks";
import WelcomeMessage from "@components/welcome-message";
import { useSession, signIn, signOut } from "next-auth/react";

const Login = () => {
const mounted = useMount();
const { isLoggedIn, logout } = useUser();
const { data: session, status } = useSession();
const router = useRouter();

useEffect(() => {
if (isLoggedIn) {
void router.push("/profile"); // Redirect to dashboard if already logged in
if (status === "authenticated") {
void router.push("/profile"); // Redirect to profile if logged in
}
}, [isLoggedIn, router]);
}, [status, router]);

if (!mounted) return null;
if (!mounted || status === "loading") {
return (
<div className="tw-fixed tw-bg-light-100 tw-top-0 tw-z-50 tw-w-screen tw-h-screen tw-flex tw-justify-center tw-items-center">
<Spinner />
</div>
);
}

if (!isLoggedIn) {
if (!session) {
return (
<>
<PageSeo title="Login" description="Login to your account" />
Expand All @@ -36,7 +41,12 @@ const Login = () => {
<WelcomeMessage />
</div>
<div className="tw-flex tw-items-center tw-w-full lg:tw-w-3/4 tw-mx-auto">
<LoginForm />
<button
onClick={() => signIn("github")}
className="tw-bg-primary tw-text-white tw-py-2 tw-px-4 tw-rounded"
>
Sign in with GitHub
</button>
</div>
</div>
</>
Expand All @@ -46,7 +56,11 @@ const Login = () => {
return (
<div className="tw-fixed tw-bg-light-100 tw-top-0 tw-z-50 tw-w-screen tw-h-screen tw-flex tw-justify-center tw-items-center">
<Spinner />
<button type="button" onClick={logout}>
<button
type="button"
onClick={() => signOut()}
className="tw-bg-red-500 tw-text-white tw-py-2 tw-px-4 tw-rounded"
>
Logout
</button>
</div>
Expand All @@ -67,4 +81,4 @@ export const getStaticProps = () => {
};
};

export default Login;
export default Login;
31 changes: 19 additions & 12 deletions src/pages/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,43 @@ import Layout01 from "@layout/layout-01";
import Breadcrumb from "@components/breadcrumb";
import ProfileBio from "@containers/profile/bio";
import Spinner from "@ui/spinner";
import { useUser } from "@contexts/user-context";
import { useMount } from "@hooks";
import { useSession, signOut } from "next-auth/react";

type PageProps = NextPage & {
Layout: typeof Layout01;
};

const Profile: PageProps = () => {
const mounted = useMount();
const { isLoggedIn, logout } = useUser();
const { data: session, status } = useSession();
const router = useRouter();

useEffect(() => {
if (!isLoggedIn) {
if (status === "unauthenticated") {
// Redirect to login if not logged in
void router.push("/login");
}
}, [isLoggedIn, router]);
}, [status, router]);

if (!mounted) return null;

if (!isLoggedIn) {
if (status === "loading") {
// Show a spinner while the session is being fetched
return (
<div className="tw-fixed tw-bg-light-100 tw-top-0 tw-z-50 tw-w-screen tw-h-screen tw-flex tw-justify-center tw-items-center">
<Spinner />
</div>
);
}

const handleLogout = () => {
logout();
if (!session) {
// This shouldn't happen due to the redirect above, but handle the case
return (
<div className="tw-fixed tw-bg-light-100 tw-top-0 tw-z-50 tw-w-screen tw-h-screen tw-flex tw-justify-center tw-items-center">
<p>You are not logged in.</p>
</div>
);
}

const handleLogout = async () => {
await signOut();
void router.push("/login");
};

Expand Down Expand Up @@ -75,4 +82,4 @@ export const getStaticProps: GetStaticProps = () => {
};
};

export default Profile;
export default Profile;
14 changes: 7 additions & 7 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@
"@widgets/*": ["components/widgets/*"],
"@fonts/*": ["public/fonts/*"]
},
"types": ["google.maps"] // Add this line
"types": ["google.maps", "next-auth"] // Add "next-auth" here
},
"include": [
"next-env.d.ts",
"next.config.js",
"src/**/*.ts",
"src/**/*.tsx",
"tailwind.config.js",
"postcss.config.js",
"next-env.d.ts",
"next.config.js",
"src/**/*.ts",
"src/**/*.tsx",
"tailwind.config.js",
"postcss.config.js",
"next-sitemap.config.js"
],
"exclude": ["node_modules"]
Expand Down
Loading
Loading