diff --git a/apps/api/prisma/migrations/20251114063002_add_completed_steps/migration.sql b/apps/api/prisma/migrations/20251114063002_add_completed_steps/migration.sql new file mode 100644 index 00000000..965fcd6a --- /dev/null +++ b/apps/api/prisma/migrations/20251114063002_add_completed_steps/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "completedSteps" JSONB; diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 229f6244..2bf9695f 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -32,15 +32,16 @@ enum SubscriptionStatus { } model User { - id String @id @default(cuid()) - email String @unique - firstName String - authMethod String - createdAt DateTime @default(now()) - lastLogin DateTime @updatedAt - accounts Account[] - payments Payment[] - subscriptions Subscription[] + id String @id @default(cuid()) + email String @unique + firstName String + authMethod String + createdAt DateTime @default(now()) + lastLogin DateTime @updatedAt + completedSteps Json? + accounts Account[] + payments Payment[] + subscriptions Subscription[] } model Account { diff --git a/apps/api/src/routers/user.ts b/apps/api/src/routers/user.ts index 2618fa3d..94205d01 100644 --- a/apps/api/src/routers/user.ts +++ b/apps/api/src/routers/user.ts @@ -1,5 +1,6 @@ import { router, publicProcedure, protectedProcedure } from "../trpc.js"; import { userService } from "../services/user.service.js"; +import { z } from "zod"; export const userRouter = router({ // get the total count of users @@ -12,4 +13,26 @@ export const userRouter = router({ const userId = ctx.user.id; return await userService.checkSubscriptionStatus(ctx.db.prisma, userId); }), + + // get user's completed steps + getCompletedSteps: protectedProcedure.query(async ({ ctx }: any) => { + const userId = ctx.user.id; + return await userService.getCompletedSteps(ctx.db.prisma, userId); + }), + + // update user's completed steps + updateCompletedSteps: protectedProcedure + .input( + z.object({ + completedSteps: z.array(z.string()), + }) + ) + .mutation(async ({ ctx, input }: any) => { + const userId = ctx.user.id; + return await userService.updateCompletedSteps( + ctx.db.prisma, + userId, + input.completedSteps + ); + }), }); diff --git a/apps/api/src/services/user.service.ts b/apps/api/src/services/user.service.ts index 3bd794fd..26ac2251 100644 --- a/apps/api/src/services/user.service.ts +++ b/apps/api/src/services/user.service.ts @@ -47,4 +47,43 @@ export const userService = { : null, }; }, + + /** + * Get user's completed steps + */ + async getCompletedSteps( + prisma: ExtendedPrismaClient | PrismaClient, + userId: string + ) { + const user = await prisma.user.findUnique({ + where: { id: userId }, + select: { completedSteps: true }, + }); + + if (!user) { + throw new Error("User not found"); + } + + const completedSteps = user.completedSteps as string[] | null; + return completedSteps || []; + }, + + /** + * Update user's completed steps + */ + async updateCompletedSteps( + prisma: ExtendedPrismaClient | PrismaClient, + userId: string, + completedSteps: string[] + ) { + const user = await prisma.user.update({ + where: { id: userId }, + data: { + completedSteps: completedSteps, + }, + select: { completedSteps: true }, + }); + + return (user.completedSteps as string[]) || []; + }, }; diff --git a/apps/web/next.config.js b/apps/web/next.config.js index fdebc20d..3819a18b 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -6,6 +6,10 @@ const nextConfig = { protocol: "https", hostname: "avatars.githubusercontent.com", }, + { + protocol: "https", + hostname: "lh3.googleusercontent.com", + }, ], }, }; diff --git a/apps/web/package.json b/apps/web/package.json index 7848f7ca..77494fc3 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -24,6 +24,7 @@ "@vercel/speed-insights": "^1.1.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "dompurify": "^3.3.0", "framer-motion": "^11.15.0", "geist": "^1.5.1", "lucide-react": "^0.456.0", @@ -41,6 +42,7 @@ "zustand": "^5.0.1" }, "devDependencies": { + "@types/dompurify": "^3.2.0", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", diff --git a/apps/web/public/images/dm.webp b/apps/web/public/images/dm.webp new file mode 100644 index 00000000..14695894 Binary files /dev/null and b/apps/web/public/images/dm.webp differ diff --git a/apps/web/public/images/doc.webp b/apps/web/public/images/doc.webp new file mode 100644 index 00000000..39599266 Binary files /dev/null and b/apps/web/public/images/doc.webp differ diff --git a/apps/web/public/images/lv-1.webp b/apps/web/public/images/lv-1.webp new file mode 100644 index 00000000..951f3a2a Binary files /dev/null and b/apps/web/public/images/lv-1.webp differ diff --git a/apps/web/public/images/module-1.webp b/apps/web/public/images/module-1.webp new file mode 100644 index 00000000..60e7cd62 Binary files /dev/null and b/apps/web/public/images/module-1.webp differ diff --git a/apps/web/public/images/ptm.webp b/apps/web/public/images/ptm.webp new file mode 100644 index 00000000..f5eeb86f Binary files /dev/null and b/apps/web/public/images/ptm.webp differ diff --git a/apps/web/public/images/sheet-1.webp b/apps/web/public/images/sheet-1.webp new file mode 100644 index 00000000..0cff34be Binary files /dev/null and b/apps/web/public/images/sheet-1.webp differ diff --git a/apps/web/public/images/sheet-2.webp b/apps/web/public/images/sheet-2.webp new file mode 100644 index 00000000..fa184986 Binary files /dev/null and b/apps/web/public/images/sheet-2.webp differ diff --git a/apps/web/src/app/(main)/(landing)/pricing/page.tsx b/apps/web/src/app/(main)/(landing)/pricing/page.tsx index c5505bec..2823888a 100644 --- a/apps/web/src/app/(main)/(landing)/pricing/page.tsx +++ b/apps/web/src/app/(main)/(landing)/pricing/page.tsx @@ -61,7 +61,7 @@ const opensoxFeatures = [ const whySub = [ { content: - "Currently, Opensox 2.0 is in progress (70% done) so till the launch, we are offering premium plan at a discounted price - $49 for the whole year", + "Currently, Opensox 2.0 is in progress (70% done) so till the launch, we are offering Pro plan at a discounted price - $49 for the whole year", }, { content: @@ -69,7 +69,7 @@ const whySub = [ }, { content: - "After the launch, this $49 offer be removed and Opensox premium will be around ~ $120 for whole year ($10/mo.)", + "After the launch, this $49 offer be removed and Opensox Pro will be around ~ $120 for whole year ($10/mo.)", }, { content: "The price of the dollar is constantly increasing.", @@ -93,17 +93,17 @@ const premiumPlanCard = { "1:1 session on finding remote jobs and internships in open-source companies.", "Quick doubts resolution.", "Personalized guidance for GSoC, LFX, Outreachy, etc", - "Access to premium Slack where you can ask anything anytime.", + "Access to Pro Slack where you can ask anything anytime.", "Support to enhance skills for open source", "GSOC proposal, resume reviews, etc.", - "Upcoming premium features", + "Upcoming Pro features", ], whatYouGetAfterLaunch: [ "Everything mentioned above", - "Advanced tool with premium filters to find open source projects", - "Premium newsletter", + "Advanced tool with Pro filters to find open source projects", + "Pro newsletter", "30 days opensox challenge sheet", - "Upcoming premium features.", + "Upcoming Pro features.", ], }; @@ -202,7 +202,7 @@ const Pricing = () => { }} className="text-center text-3xl tracking-tight font-medium" > - Why should you subscribe to Opensox premium now? + Why should you subscribe to Opensox Pro now?
@@ -377,7 +377,7 @@ const SecondaryPricingCard = () => {
{username}

{showPremium && (
-

Opensox Premium

+

Opensox Pro

)}
@@ -445,14 +445,14 @@ const TestimonialsSection = () => { id: 1, username: "Tarun Parmar", content: - "Getting the Opensox Premium Subscription has been such a game-changer for me. I really like the personal touch in the way the team guides you-it feels like someone is genuinely there to help you navigate. It gave me the initial push I needed and made it so much easier to cut through all the chaos and focus on the right and simple steps. The best part is, it helps you start your open source journey quickly and I know I can reach out to the team anytime. Honestly, it's been an awesome experience so far!", + "Getting the Opensox Pro Subscription has been such a game-changer for me. I really like the personal touch in the way the team guides you-it feels like someone is genuinely there to help you navigate. It gave me the initial push I needed and made it so much easier to cut through all the chaos and focus on the right and simple steps. The best part is, it helps you start your open source journey quickly and I know I can reach out to the team anytime. Honestly, it's been an awesome experience so far!", column: 1, }, { id: 2, username: "Daksh Yadav", content: - "My experience with your guidance and opensox has been great. Your tips have really helped in doing my tasks quicker and better. And I would definitely recommend others to opt for opensox premium.", + "My experience with your guidance and opensox has been great. Your tips have really helped in doing my tasks quicker and better. And I would definitely recommend others to opt for opensox Pro.", column: 1, }, { @@ -462,7 +462,7 @@ const TestimonialsSection = () => {

Okay so there are a few things I genuinely value about OpenSox - Premium, and I'll focus on the core points because everything + Pro, and I'll focus on the core points because everything else is just a natural extension of these.

diff --git a/apps/web/src/app/(main)/legal/terms/page.tsx b/apps/web/src/app/(main)/legal/terms/page.tsx index 1f528331..50f5fab9 100644 --- a/apps/web/src/app/(main)/legal/terms/page.tsx +++ b/apps/web/src/app/(main)/legal/terms/page.tsx @@ -59,7 +59,7 @@ export default function TermsOfServicePage() { opportunities
  • - Premium Features: Access to personalized + Pro Features: Access to personalized mentoring, exclusive newsletter, open-source jobs and internship opportunities, and our 30-day contribution challenge
  • @@ -136,10 +136,10 @@ export default function TermsOfServicePage() { {/* Section 4 */}

    - 4. Premium Subscription Services + 4. Pro Subscription Services

    - Opensox.ai offers premium subscription plans with enhanced + Opensox.ai offers Pro subscription plans with enhanced features including:

    - Payment Terms: Premium subscriptions are billed + Payment Terms: Pro subscriptions are billed in advance on a monthly or annual basis. All fees are non-refundable except as required by law. You may cancel your subscription at any time, and cancellation will take effect at the @@ -170,7 +170,7 @@ export default function TermsOfServicePage() {

    Price Changes: We reserve the right to modify subscription pricing with at least 30 days' notice. Continued use - of premium services after a price change constitutes acceptance of + of Pro services after a price change constitutes acceptance of the new pricing.

    @@ -262,7 +262,7 @@ export default function TermsOfServicePage() { 8. Mentoring Services

    - Premium subscribers may access personalized mentoring services. + Pro subscribers may access personalized mentoring services. Please note: