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 0000000..965fcd6 --- /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 229f624..2bf9695 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 2618fa3..94205d0 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 3bd794f..26ac225 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 fdebc20..3819a18 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 7848f7c..77494fc 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 0000000..1469589 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 0000000..3959926 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 0000000..951f3a2 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 0000000..60e7cd6 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 0000000..f5eeb86 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 0000000..0cff34b 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 0000000..fa18498 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 c5505be..2823888 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 1f52833..50f5fab 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: