├── .eslintrc.json ├── public ├── cry.png ├── icon.png ├── img1.png ├── img2.png ├── img3.png ├── img4.png ├── love.png ├── robot.png ├── correct.wav ├── finish.mp3 ├── question.png ├── search.png ├── depression.png ├── incorrect.wav ├── robot-error.png ├── js.svg ├── heart.svg ├── next.svg ├── php.svg ├── go.svg └── java.svg ├── src ├── app │ ├── favicon.ico │ ├── (main) │ │ ├── (shop) │ │ │ └── shop │ │ │ │ ├── loading.tsx │ │ │ │ └── page.tsx │ │ ├── (learn) │ │ │ └── learn │ │ │ │ ├── loading.tsx │ │ │ │ └── page.tsx │ │ ├── (quests) │ │ │ └── quests │ │ │ │ ├── loading.tsx │ │ │ │ └── page.tsx │ │ ├── (courses) │ │ │ ├── courses │ │ │ │ ├── loading.tsx │ │ │ │ └── page.tsx │ │ │ └── _components │ │ │ │ ├── card.tsx │ │ │ │ └── list.tsx │ │ ├── (profile) │ │ │ ├── profile │ │ │ │ ├── loading.tsx │ │ │ │ └── [profileId] │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── not-found.tsx │ │ │ └── _components │ │ │ │ ├── back-redirect.tsx │ │ │ │ ├── private-image-banner.tsx │ │ │ │ ├── solved-challenges.tsx │ │ │ │ ├── active-course-card.tsx │ │ │ │ ├── list.tsx │ │ │ │ ├── card.tsx │ │ │ │ ├── profile-hide-component.tsx │ │ │ │ └── bio-form.tsx │ │ ├── (leaderboard) │ │ │ └── leaderboard │ │ │ │ ├── loading.tsx │ │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── (challenges) │ │ ├── challenges │ │ │ └── [challengeId] │ │ │ │ ├── loading.tsx │ │ │ │ ├── error.tsx │ │ │ │ └── page.tsx │ │ └── _components │ │ │ ├── bubble-tag.tsx │ │ │ ├── challenge.tsx │ │ │ ├── result-card.tsx │ │ │ ├── finished-screen.tsx │ │ │ ├── footer.tsx │ │ │ └── challenge-option.tsx │ ├── font.ts │ ├── (landing) │ │ ├── page.tsx │ │ ├── layout.tsx │ │ └── _components │ │ │ ├── footer.tsx │ │ │ ├── contributors-section.tsx │ │ │ ├── release-section.tsx │ │ │ ├── header.tsx │ │ │ └── hero-section.tsx │ ├── (auth) │ │ ├── sign-in │ │ │ └── [[...sign-in]] │ │ │ │ └── page.tsx │ │ ├── sign-up │ │ │ └── [[...sign-up]] │ │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── not-found.tsx │ ├── layout.tsx │ ├── api │ │ ├── users │ │ │ └── route.ts │ │ └── webhooks │ │ │ └── clerk │ │ │ └── route.ts │ ├── globals.css │ ├── (privacy) │ │ └── privacy │ │ │ └── page.tsx │ └── (terms) │ │ └── terms │ │ └── page.tsx ├── shared │ ├── constant.ts │ ├── contributors-list.ts │ └── release-list.ts ├── queries │ ├── quests-queries.ts │ ├── user-queries.ts │ ├── user-profile-view-queries.ts │ ├── quests-progress-queries.ts │ ├── courses-queries.ts │ ├── user-progress-queries.ts │ └── challenges-queries.ts ├── lib │ └── utils.ts ├── config │ └── site.ts ├── db │ └── index.ts ├── components │ ├── feed-wrapper.tsx │ ├── theme-provider.tsx │ ├── sticky-wrapper.tsx │ ├── code-block │ │ └── code-block.tsx │ ├── search-header.tsx │ ├── header.tsx │ ├── provider │ │ └── modal-provider.tsx │ ├── ui │ │ ├── label.tsx │ │ ├── separator.tsx │ │ ├── progress.tsx │ │ ├── input.tsx │ │ ├── sonner.tsx │ │ ├── switch.tsx │ │ ├── badge.tsx │ │ ├── tooltip.tsx │ │ ├── avatar.tsx │ │ ├── quest-item.tsx │ │ ├── scroll-area.tsx │ │ ├── button.tsx │ │ ├── card.tsx │ │ └── table.tsx │ ├── action-tooltip.tsx │ ├── user-button-container.tsx │ ├── wrapper-leaderboard.tsx │ ├── ads-card.tsx │ ├── main-layout-header.tsx │ ├── mode-toggle.tsx │ ├── comment-sheet │ │ ├── index.tsx │ │ ├── comment-form.tsx │ │ └── comment-scroll-area.tsx │ ├── user-progress.tsx │ ├── modal │ │ ├── exit-modal.tsx │ │ ├── error-alert-modal.tsx │ │ ├── profile-view-avatar-modal.tsx │ │ ├── no-enough-hearts-modal.tsx │ │ └── search-users-modal.tsx │ ├── challenges-data-table │ │ ├── columns.tsx │ │ └── index.tsx │ ├── user-item.tsx │ ├── leaderboard-data-table │ │ ├── columns.tsx │ │ └── index.tsx │ ├── profile-view-avatars.tsx │ ├── quests.tsx │ ├── side-bar.tsx │ ├── mobile-side-bar.tsx │ └── main-layout-responsive-header.tsx ├── store │ ├── use-exit-modal-store.ts │ ├── use-search-users-store.ts │ ├── use-footer-card-store.ts │ ├── use-no-enough-hearts-modal-store.ts │ └── use-user-profile-view-avatar-modal-store.ts ├── middleware.ts ├── firebase │ ├── index.ts │ └── actions │ │ └── comments-action.ts ├── actions │ ├── user-profile-view-actions.ts │ ├── user-action.ts │ ├── quest-progress-action.ts │ └── user-progress-action.ts └── types.ts ├── next.config.mjs ├── postcss.config.mjs ├── prisma ├── reset.ts ├── add.ts └── schema.prisma ├── components.json ├── .gitignore ├── tsconfig.json ├── .env-example ├── LICENSE ├── package.json ├── tailwind.config.ts └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /public/cry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/cry.png -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/icon.png -------------------------------------------------------------------------------- /public/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/img1.png -------------------------------------------------------------------------------- /public/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/img2.png -------------------------------------------------------------------------------- /public/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/img3.png -------------------------------------------------------------------------------- /public/img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/img4.png -------------------------------------------------------------------------------- /public/love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/love.png -------------------------------------------------------------------------------- /public/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/robot.png -------------------------------------------------------------------------------- /public/correct.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/correct.wav -------------------------------------------------------------------------------- /public/finish.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/finish.mp3 -------------------------------------------------------------------------------- /public/question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/question.png -------------------------------------------------------------------------------- /public/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/search.png -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /public/depression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/depression.png -------------------------------------------------------------------------------- /public/incorrect.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/incorrect.wav -------------------------------------------------------------------------------- /public/robot-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kei-K23/mentor/HEAD/public/robot-error.png -------------------------------------------------------------------------------- /src/shared/constant.ts: -------------------------------------------------------------------------------- 1 | export const POINT_TO_FILL = 10; 2 | export const POINT_TO_FULL_FILL = 50; -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /src/queries/quests-queries.ts: -------------------------------------------------------------------------------- 1 | import { db } from "@/db" 2 | 3 | export const getAllQuests = async () => { 4 | return await db.quest.findMany(); 5 | } 6 | 7 | -------------------------------------------------------------------------------- /src/shared/contributors-list.ts: -------------------------------------------------------------------------------- 1 | export const contributors = [ 2 | { 3 | name: "Kei-K", 4 | githubLink: "https://github.com/Kei-K23", 5 | } 6 | ] -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /src/queries/user-queries.ts: -------------------------------------------------------------------------------- 1 | import { db } from "@/db" 2 | 3 | export const getUserByExternalUserId = async (externalUserId: string) => { 4 | return db.user.findUnique({ 5 | where: { 6 | externalUserId 7 | } 8 | }) 9 | } -------------------------------------------------------------------------------- /src/config/site.ts: -------------------------------------------------------------------------------- 1 | export const siteConfig = { 2 | title: "Mentor", 3 | description: "Mentor is an open-source web application for learning, practicing and mastering programming languages and craft interview questions. The goal of this project to improve the developer community.", 4 | } -------------------------------------------------------------------------------- /src/db/index.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | declare global { 4 | var prisma: PrismaClient | undefined; 5 | } 6 | 7 | export const db = globalThis.prisma || new PrismaClient(); 8 | 9 | if (process.env.NODE_ENV !== "production") globalThis.prisma = db; 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/feed-wrapper.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | type FeedWrapperProps = { 4 | children: React.ReactNode; 5 | }; 6 | 7 | const FeedWrapper = ({ children }: FeedWrapperProps) => { 8 | return
9 | A place for programmers to exploring and practice programming language 10 | and interview questions 11 |
12 |User doest not exist.
10 | 19 | Back to profile 20 | 21 |15 | This user is preferred to hide the personal information! 16 |
17 |18 | You can view this account when owner public their profile. 19 |
20 |{text}
28 |14 | {pathname} is not a valid route. 15 |
16 | 25 | Back to Home 26 | 27 |No leaderboard data.
25 | )} 26 |30 | {title} 31 |
32 |{description}
33 |21 | This could be third-party error because honestly Mentor only use free 22 | services or due to internal code issues. 23 |
24 | 31 | 32 | Back to Home 33 | 34 |32 | {title} 33 |
34 |{description}
35 |20 | This project grows with the contributions of these contributors. 21 |
22 |{c.name}
38 | 39 | ))} 40 |{r.description}
25 | {r.features.length && ( 26 |33 | {quest.title} 34 |
35 | 36 |50 | {title} 51 |
52 |{description}
53 |{ 59 | if (notEditable) return; 60 | setIsEdit(true); 61 | }} 62 | > 63 | {bio === "" ? "This user is not provide bio." : bio} 64 |
65 |57 | {row.original.difficulty} 58 |
59 |37 | {index + 1} 38 |
39 | )} 40 | 41 |{userProgress.points} XP
60 |26 | {row.index + 1} 27 |
28 | ); 29 | }, 30 | }, 31 | { 32 | accessorKey: "user", 33 | header: "User", 34 | cell: ({ row }) => { 35 | return ( 36 |{row.original.points} XP
63 |No profile views.
55 | )} 56 |