-
-
Save adrianhajdin/a453d745c2361ae4183b421f577a0715 to your computer and use it in GitHub Desktop.
| import { User, Session } from 'next-auth' | |
| export type FormState = { | |
| title: string; | |
| description: string; | |
| image: string; | |
| liveSiteUrl: string; | |
| githubUrl: string; | |
| category: string; | |
| }; | |
| export interface ProjectInterface { | |
| title: string; | |
| description: string; | |
| image: string; | |
| liveSiteUrl: string; | |
| githubUrl: string; | |
| category: string; | |
| id: string; | |
| createdBy: { | |
| name: string; | |
| email: string; | |
| avatarUrl: string; | |
| id: string; | |
| }; | |
| } | |
| export interface UserProfile { | |
| id: string; | |
| name: string; | |
| email: string; | |
| description: string | null; | |
| avatarUrl: string; | |
| githubUrl: string | null; | |
| linkedinUrl: string | null; | |
| projects: { | |
| edges: { node: ProjectInterface }[]; | |
| pageInfo: { | |
| hasPreviousPage: boolean; | |
| hasNextPage: boolean; | |
| startCursor: string; | |
| endCursor: string; | |
| }; | |
| }; | |
| } | |
| export interface SessionInterface extends Session { | |
| user: User & { | |
| id: string; | |
| name: string; | |
| email: string; | |
| avatarUrl: string; | |
| }; | |
| } | |
| export interface ProjectForm { | |
| title: string; | |
| description: string; | |
| image: string; | |
| liveSiteUrl: string; | |
| githubUrl: string; | |
| category: string; | |
| } |
| export const NavLinks = [ | |
| { href: '/', key: 'Inspiration', text: 'Inspiration' }, | |
| { href: '/', key: 'Find Projects', text: 'Find Projects' }, | |
| { href: '/', key: 'Learn Development', text: 'Learn Development' }, | |
| { href: '/', key: 'Career Advancement', text: 'Career Advancement' }, | |
| { href: '/', key: 'Hire Developers', text: 'Hire Developers' } | |
| ]; | |
| export const categoryFilters = [ | |
| "Frontend", | |
| "Backend", | |
| "Full-Stack", | |
| "Mobile", | |
| "UI/UX", | |
| "Game Dev", | |
| "DevOps", | |
| "Data Science", | |
| "Machine Learning", | |
| "Cybersecurity", | |
| "Blockchain", | |
| "E-commerce", | |
| "Chatbots" | |
| ] | |
| export const footerLinks = [ | |
| { | |
| title: 'For developers', | |
| links: [ | |
| 'Go Pro!', | |
| 'Explore development work', | |
| 'Development blog', | |
| 'Code podcast', | |
| 'Open-source projects', | |
| 'Refer a Friend', | |
| 'Code of conduct', | |
| ], | |
| }, | |
| { | |
| title: 'Hire developers', | |
| links: [ | |
| 'Post a job opening', | |
| 'Post a freelance project', | |
| 'Search for developers', | |
| ], | |
| }, | |
| { | |
| title: 'Brands', | |
| links: [ | |
| 'Advertise with us', | |
| ], | |
| }, | |
| { | |
| title: 'Company', | |
| links: [ | |
| 'About', | |
| 'Careers', | |
| 'Support', | |
| 'Media kit', | |
| 'Testimonials', | |
| 'API', | |
| 'Terms of service', | |
| 'Privacy policy', | |
| 'Cookie policy', | |
| ], | |
| }, | |
| { | |
| title: 'Directories', | |
| links: [ | |
| 'Development jobs', | |
| 'Developers for hire', | |
| 'Freelance developers for hire', | |
| 'Tags', | |
| 'Places', | |
| ], | |
| }, | |
| { | |
| title: 'Development assets', | |
| links: [ | |
| 'Code Marketplace', | |
| 'GitHub Marketplace', | |
| 'NPM Registry', | |
| 'Packagephobia', | |
| ], | |
| }, | |
| { | |
| title: 'Development Resources', | |
| links: [ | |
| 'Freelancing', | |
| 'Development Hiring', | |
| 'Development Portfolio', | |
| 'Development Education', | |
| 'Creative Process', | |
| 'Development Industry Trends', | |
| ], | |
| }, | |
| ]; | |
| @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"); | |
| @tailwind base; | |
| @tailwind components; | |
| @tailwind utilities; | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: Inter; | |
| } | |
| .flexCenter { | |
| @apply flex justify-center items-center; | |
| } | |
| .flexBetween { | |
| @apply flex justify-between items-center; | |
| } | |
| .flexStart { | |
| @apply flex items-center justify-start; | |
| } | |
| .text-small { | |
| @apply text-sm font-medium; | |
| } | |
| .paddings { | |
| @apply lg:px-20 py-6 px-5; | |
| } | |
| ::-webkit-scrollbar { | |
| width: 5px; | |
| height: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #888; | |
| border-radius: 12px; | |
| } | |
| .modal-head-text { | |
| @apply md:text-5xl text-3xl font-extrabold text-left max-w-5xl w-full; | |
| } | |
| .no-result-text { | |
| @apply w-full text-center my-10 px-2; | |
| } | |
| /* Project Details */ | |
| .user-actions_section { | |
| @apply fixed max-md:hidden flex gap-4 flex-col right-10 top-20; | |
| } | |
| .user-info { | |
| @apply flex flex-wrap whitespace-nowrap text-sm font-normal gap-2 w-full; | |
| } | |
| /* Home */ | |
| .projects-grid { | |
| @apply grid xl:grid-cols-4 md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-10 mt-10 w-full; | |
| } | |
| /* Project Actions */ | |
| .edit-action_btn { | |
| @apply p-3 text-gray-100 bg-light-white-400 rounded-lg text-sm font-medium; | |
| } | |
| .delete-action_btn { | |
| @apply p-3 text-gray-100 hover:bg-red-600 rounded-lg text-sm font-medium; | |
| } | |
| /* Related Project Card */ | |
| .related_project-card { | |
| @apply flex-col rounded-2xl min-w-[210px] min-h-[197px]; | |
| } | |
| .related_project-card_title { | |
| @apply justify-end items-end w-full h-1/3 bg-gradient-to-b from-transparent to-black/50 rounded-b-2xl gap-2 absolute bottom-0 right-0 font-semibold text-lg text-white p-4; | |
| } | |
| .related_projects-grid { | |
| @apply grid xl:grid-cols-4 md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-8 mt-5; | |
| } | |
| /* Custom Menu */ | |
| .custom_menu-btn { | |
| @apply gap-4 w-full rounded-md bg-light-white-100 p-4 text-base outline-none capitalize; | |
| } | |
| .custom_menu-items { | |
| @apply flex-col absolute left-0 mt-2 xs:min-w-[300px] w-fit max-h-64 origin-top-right rounded-xl bg-white border border-nav-border shadow-menu overflow-y-auto; | |
| } | |
| .custom_menu-item { | |
| @apply text-left w-full px-5 py-2 text-sm hover:bg-light-white-100 self-start whitespace-nowrap capitalize; | |
| } | |
| /* Footer */ | |
| .footer { | |
| @apply flex-col paddings w-full gap-20 bg-light-white; | |
| } | |
| .footer_copyright { | |
| @apply max-sm:flex-col w-full text-sm font-normal; | |
| } | |
| .footer_column { | |
| @apply flex-1 flex flex-col gap-3 text-sm min-w-max; | |
| } | |
| /* Form Field */ | |
| .form_field-input { | |
| @apply w-full outline-0 bg-light-white-100 rounded-xl p-4; | |
| } | |
| /* Modal */ | |
| .modal { | |
| @apply fixed z-10 left-0 right-0 top-0 bottom-0 mx-auto bg-black/80; | |
| } | |
| .modal_wrapper { | |
| @apply flex justify-start items-center flex-col absolute h-[95%] w-full bottom-0 bg-white rounded-t-3xl lg:px-40 px-8 pt-14 pb-72 overflow-auto; | |
| } | |
| /* Navbar */ | |
| .navbar { | |
| @apply py-5 px-8 border-b border-nav-border gap-4; | |
| } | |
| /* Profile Menu */ | |
| .profile_menu-items { | |
| @apply flex-col absolute right-1/2 translate-x-1/2 mt-3 p-7 sm:min-w-[300px] min-w-max rounded-xl bg-white border border-nav-border shadow-menu; | |
| } | |
| /* Profile Card */ | |
| .profile_card-title { | |
| @apply justify-end items-end w-full h-1/3 bg-gradient-to-b from-transparent to-black/50 rounded-b-2xl gap-2 absolute bottom-0 right-0 font-semibold text-lg text-white p-4; | |
| } | |
| /* Project Form */ | |
| .form { | |
| @apply flex-col w-full lg:pt-24 pt-12 gap-10 text-lg max-w-5xl mx-auto; | |
| } | |
| .form_image-container { | |
| @apply w-full lg:min-h-[400px] min-h-[200px] relative; | |
| } | |
| .form_image-label { | |
| @apply z-10 text-center w-full h-full p-20 text-gray-100 border-2 border-gray-50 border-dashed; | |
| } | |
| .form_image-input { | |
| @apply absolute z-30 w-full opacity-0 h-full cursor-pointer; | |
| } | |
| /* Profile Projects */ | |
| .profile_projects { | |
| @apply grid xl:grid-cols-4 md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-8 mt-5; | |
| } |
| export const createProjectMutation = ` | |
| mutation CreateProject($input: ProjectCreateInput!) { | |
| projectCreate(input: $input) { | |
| project { | |
| id | |
| title | |
| description | |
| createdBy { | |
| name | |
| } | |
| } | |
| } | |
| } | |
| `; | |
| export const updateProjectMutation = ` | |
| mutation UpdateProject($id: ID!, $input: ProjectUpdateInput!) { | |
| projectUpdate(by: { id: $id }, input: $input) { | |
| project { | |
| id | |
| title | |
| description | |
| createdBy { | |
| name | |
| } | |
| } | |
| } | |
| } | |
| `; | |
| export const deleteProjectMutation = ` | |
| mutation DeleteProject($id: ID!) { | |
| projectDelete(by: { id: $id }) { | |
| deletedId | |
| } | |
| } | |
| `; | |
| export const createUserMutation = ` | |
| mutation CreateUser($input: UserCreateInput!) { | |
| userCreate(input: $input) { | |
| user { | |
| name | |
| avatarUrl | |
| description | |
| githubUrl | |
| linkedinUrl | |
| id | |
| } | |
| } | |
| } | |
| `; | |
| export const projectsQuery = ` | |
| query getProjects($category: String, $endCursor: String) { | |
| projectSearch(first: 8, after: $endCursor, filter: {category: {eq: $category}}) { | |
| pageInfo { | |
| hasNextPage | |
| hasPreviousPage | |
| startCursor | |
| endCursor | |
| } | |
| edges { | |
| node { | |
| title | |
| githubUrl | |
| description | |
| liveSiteUrl | |
| id | |
| image | |
| category | |
| createdBy { | |
| id | |
| name | |
| avatarUrl | |
| } | |
| } | |
| } | |
| } | |
| } | |
| `; | |
| export const getProjectByIdQuery = ` | |
| query GetProjectById($id: ID!) { | |
| project(by: { id: $id }) { | |
| id | |
| title | |
| description | |
| image | |
| liveSiteUrl | |
| githubUrl | |
| category | |
| createdBy { | |
| id | |
| name | |
| avatarUrl | |
| } | |
| } | |
| } | |
| `; | |
| export const getUserQuery = ` | |
| query GetUser($email: String!) { | |
| user(by: { email: $email }) { | |
| id | |
| name | |
| avatarUrl | |
| description | |
| githubUrl | |
| linkedinUrl | |
| } | |
| } | |
| `; | |
| export const getProjectsOfUserQuery = ` | |
| query getUserProjects($id: ID!, $last: Int = 4) { | |
| user(by: { id: $id }) { | |
| id | |
| name | |
| description | |
| avatarUrl | |
| githubUrl | |
| linkedinUrl | |
| projects(last: $last) { | |
| edges { | |
| node { | |
| id | |
| title | |
| image | |
| } | |
| } | |
| } | |
| } | |
| } | |
| `; |
| import { ProjectInterface, UserProfile } from '@/common.types' | |
| import Image from 'next/image' | |
| import Link from 'next/link' | |
| import Button from "./Button"; | |
| import ProjectCard from './ProjectCard'; | |
| type Props = { | |
| user: UserProfile; | |
| } | |
| const ProfilePage = ({ user }: Props) => ( | |
| <section className='flexCenter flex-col max-w-10xl w-full mx-auto paddings'> | |
| <section className="flexBetween max-lg:flex-col gap-10 w-full"> | |
| <div className='flex items-start flex-col w-full'> | |
| <Image src={user?.avatarUrl} width={100} height={100} className="rounded-full" alt="user image" /> | |
| <p className="text-4xl font-bold mt-10">{user?.name}</p> | |
| <p className="md:text-5xl text-3xl font-extrabold md:mt-10 mt-5 max-w-lg">I’m Software Engineer at JSM 👋</p> | |
| <div className="flex mt-8 gap-5 w-full flex-wrap"> | |
| <Button | |
| title="Follow" | |
| leftIcon="/plus-round.svg" | |
| bgColor="bg-light-white-400 !w-max" | |
| textColor="text-black-100" | |
| /> | |
| <Link href={`mailto:${user?.email}`}> | |
| <Button title="Hire Me" leftIcon="/email.svg" /> | |
| </Link> | |
| </div> | |
| </div> | |
| {user?.projects?.edges?.length > 0 ? ( | |
| <Image | |
| src={user?.projects?.edges[0]?.node?.image} | |
| alt="project image" | |
| width={739} | |
| height={554} | |
| className='rounded-xl object-contain' | |
| /> | |
| ) : ( | |
| <Image | |
| src="/profile-post.png" | |
| width={739} | |
| height={554} | |
| alt="project image" | |
| className='rounded-xl' | |
| /> | |
| )} | |
| </section> | |
| <section className="flexStart flex-col lg:mt-28 mt-16 w-full"> | |
| <p className="w-full text-left text-lg font-semibold">Recent Work</p> | |
| <div className="profile_projects"> | |
| {user?.projects?.edges?.map( | |
| ({ node }: { node: ProjectInterface }) => ( | |
| <ProjectCard | |
| key={`${node?.id}`} | |
| id={node?.id} | |
| image={node?.image} | |
| title={node?.title} | |
| name={user.name} | |
| avatarUrl={user.avatarUrl} | |
| userId={user.id} | |
| /> | |
| ) | |
| )} | |
| </div> | |
| </section> | |
| </section> | |
| ) | |
| export default ProfilePage |
| import Image from "next/image" | |
| import Link from "next/link" | |
| import { getCurrentUser } from "@/lib/session" | |
| import { getProjectDetails } from "@/lib/actions" | |
| import Modal from "@/components/Modal" | |
| // import ProjectActions from "@/components/ProjectActions" | |
| import RelatedProjects from "@/components/RelatedProjects" | |
| import { ProjectInterface } from "@/common.types" | |
| import ProjectActions from "@/components/ProjectActions" | |
| const Project = async ({ params: { id } }: { params: { id: string } }) => { | |
| const session = await getCurrentUser() | |
| const result = await getProjectDetails(id) as { project?: ProjectInterface} | |
| if (!result?.project) return ( | |
| <p className="no-result-text">Failed to fetch project info</p> | |
| ) | |
| const projectDetails = result?.project | |
| const renderLink = () => `/profile/${projectDetails?.createdBy?.id}` | |
| return ( | |
| <Modal> | |
| <section className="flexBetween gap-y-8 max-w-4xl max-xs:flex-col w-full"> | |
| <div className="flex-1 flex items-start gap-5 w-full max-xs:flex-col"> | |
| <Link href={renderLink()}> | |
| <Image | |
| src={projectDetails?.createdBy?.avatarUrl} | |
| width={50} | |
| height={50} | |
| alt="profile" | |
| className="rounded-full" | |
| /> | |
| </Link> | |
| <div className="flex-1 flexStart flex-col gap-1"> | |
| <p className="self-start text-lg font-semibold"> | |
| {projectDetails?.title} | |
| </p> | |
| <div className="user-info"> | |
| <Link href={renderLink()}> | |
| {projectDetails?.createdBy?.name} | |
| </Link> | |
| <Image src="/dot.svg" width={4} height={4} alt="dot" /> | |
| <Link href={`/?category=${projectDetails.category}`} className="text-primary-purple font-semibold"> | |
| {projectDetails?.category} | |
| </Link> | |
| </div> | |
| </div> | |
| </div> | |
| {session?.user?.email === projectDetails?.createdBy?.email && ( | |
| <div className="flex justify-end items-center gap-2"> | |
| <ProjectActions projectId={projectDetails?.id} /> | |
| </div> | |
| )} | |
| </section> | |
| <section className="mt-14"> | |
| <Image | |
| src={`${projectDetails?.image}`} | |
| className="object-cover rounded-2xl" | |
| width={1064} | |
| height={798} | |
| alt="poster" | |
| /> | |
| </section> | |
| <section className="flexCenter flex-col mt-20"> | |
| <p className="max-w-5xl text-xl font-normal"> | |
| {projectDetails?.description} | |
| </p> | |
| <div className="flex flex-wrap mt-5 gap-5"> | |
| <Link href={projectDetails?.githubUrl} target="_blank" rel="noreferrer" className="flexCenter gap-2 tex-sm font-medium text-primary-purple"> | |
| 🖥 <span className="underline">Github</span> | |
| </Link> | |
| <Image src="/dot.svg" width={4} height={4} alt="dot" /> | |
| <Link href={projectDetails?.liveSiteUrl} target="_blank" rel="noreferrer" className="flexCenter gap-2 tex-sm font-medium text-primary-purple"> | |
| 🚀 <span className="underline">Live Site</span> | |
| </Link> | |
| </div> | |
| </section> | |
| <section className="flexCenter w-full gap-8 mt-28"> | |
| <span className="w-full h-0.5 bg-light-white-200" /> | |
| <Link href={renderLink()} className="min-w-[82px] h-[82px]"> | |
| <Image | |
| src={projectDetails?.createdBy?.avatarUrl} | |
| className="rounded-full" | |
| width={82} | |
| height={82} | |
| alt="profile image" | |
| /> | |
| </Link> | |
| <span className="w-full h-0.5 bg-light-white-200" /> | |
| </section> | |
| <RelatedProjects userId={projectDetails?.createdBy?.id} projectId={projectDetails?.id} /> | |
| </Modal> | |
| ) | |
| } | |
| export default Project |
| /** @type {import('tailwindcss').Config} */ | |
| module.exports = { | |
| content: [ | |
| './pages/**/*.{js,ts,jsx,tsx,mdx}', | |
| './components/**/*.{js,ts,jsx,tsx,mdx}', | |
| './app/**/*.{js,ts,jsx,tsx,mdx}', | |
| ], | |
| theme: { | |
| extend: { | |
| colors: { | |
| 'nav-border': '#EBEAEA', | |
| 'light-white': '#FAFAFB', | |
| 'light-white-100': '#F1F4F5', | |
| 'light-white-200': '#d7d7d7', | |
| 'light-white-300': '#F3F3F4', | |
| 'light-white-400': '#E2E5F1', | |
| 'light-white-500': '#E4E4E4', | |
| gray: '#4D4A4A', | |
| 'gray-100': '#3d3d4e', | |
| 'black-100': '#252525', | |
| 'primary-purple': '#9747FF', | |
| 'gray-50': '#D9D9D9', | |
| }, | |
| boxShadow: { | |
| menu: '0px 159px 95px rgba(13,12,34,0.01), 0px 71px 71px rgba(13,12,34,0.02), 0px 18px 39px rgba(13,12,34,0.02), 0px 0px 0px rgba(13,12,34,0.02)', | |
| }, | |
| screens: { | |
| 'xs': '400px', | |
| }, | |
| maxWidth: { | |
| '10xl': '1680px' | |
| } | |
| }, | |
| }, | |
| plugins: [], | |
| }; |
You should add Token folder and add NEXTAUTH_SECRET in .env
for this error
[next-auth][error][JWT_SESSION_ERROR] https://next-auth.js.org/errors#jwt_session_error jwt malformed { message: 'jwt malformed', stack: 'JsonWebTokenError: jwt malformed\n' + ' at module.exports [as verify] (webpack-internal:///(rsc)/./node_modules/jsonwebtoken/verify.js:72:21)\n' + ' at Object.decode (webpack-internal:///(rsc)/./lib/session.ts:33:86)\n' + ' at Object.session (webpack-internal:///(rsc)/./node_modules/next-auth/core/routes/session.js:25:44)\n' + ' at AuthHandler (webpack-internal:///(rsc)/./node_modules/next-auth/core/index.js:161:50)\n' + ' at async getServerSession (webpack-internal:///(rsc)/./node_modules/next-auth/next/index.js:126:21)\n' + ' at async getCurrentUser (webpack-internal:///(rsc)/./lib/session.ts:74:21)\n' + ' at async Navbar (webpack-internal:///(rsc)/./components/Navbar.tsx:21:21)', name: 'JsonWebTokenError' }
Solve
You should add Token folder and add NEXTAUTH_SECRET in .env
what you mean by Token folder?
I am also facing this. You should add Token folder and add NEXTAUTH_SECRET in .env
Anyone wanted to help me?
there is no token folder, just the two .env files in the root and in the grafbase folder.
[next-auth][error][JWT_SESSION_ERROR] https://next-auth.js.org/errors#jwt_session_error jwt malformed { message: 'jwt malformed', stack: 'JsonWebTokenError: jwt malformed\n' + ' at module.exports [as verify] (webpack-internal:///(rsc)/./node_modules/jsonwebtoken/verify.js:72:21)\n' + ' at Object.decode (webpack-internal:///(rsc)/./lib/session.ts:33:86)\n' + ' at Object.session (webpack-internal:///(rsc)/./node_modules/next-auth/core/routes/session.js:25:44)\n' + ' at AuthHandler (webpack-internal:///(rsc)/./node_modules/next-auth/core/index.js:161:50)\n' + ' at async getServerSession (webpack-internal:///(rsc)/./node_modules/next-auth/next/index.js:126:21)\n' + ' at async getCurrentUser (webpack-internal:///(rsc)/./lib/session.ts:74:21)\n' + ' at async Navbar (webpack-internal:///(rsc)/./components/Navbar.tsx:21:21)', name: 'JsonWebTokenError' }jwt malformed
i literally tried everything i know,
i put the auth secret with the provider and i've checked everything, but i get access denied after tryin to signin with google,
nothing works for me.