View and manage your subscribers
10 |76 | {apiKey} 77 |
78 |Update your email preferences or unsubscribe here
\n© 2024 Becodemy Newsletter
\n\n 228 Park Ave S, #29976, New York, New York 10003, United States \n | \n
', 43 | }, 44 | }, 45 | ], 46 | values: { 47 | backgroundColor: "#2c81e5", 48 | padding: "0px", 49 | _meta: { 50 | htmlID: "u_column_1", 51 | htmlClassNames: "u_column", 52 | }, 53 | }, 54 | }, 55 | ], 56 | values: { 57 | backgroundImage: { 58 | fullWidth: true, 59 | repeat: "no-repeat", 60 | size: "custom", 61 | position: "center", 62 | customPosition: ["50%", "50%"], 63 | }, 64 | padding: "0px", 65 | _meta: { 66 | htmlID: "u_row_1", 67 | htmlClassNames: "u_row", 68 | }, 69 | selectable: true, 70 | draggable: true, 71 | duplicatable: true, 72 | deletable: true, 73 | hideable: true, 74 | }, 75 | }, 76 | ], 77 | values: { 78 | popupPosition: "center", 79 | popupWidth: "600px", 80 | popupHeight: "auto", 81 | borderRadius: "10px", 82 | contentAlign: "center", 83 | contentVerticalAlign: "center", 84 | contentWidth: "500px", 85 | fontFamily: { 86 | label: "Arial", 87 | value: "arial,helvetica,sans-serif", 88 | }, 89 | popupBackgroundColor: "#FFFFFF", 90 | popupOverlay_backgroundColor: "rgba(0, 0, 0, 0.1)", 91 | popupCloseButton_position: "top-right", 92 | popupCloseButton_backgroundColor: "#DDDDDD", 93 | popupCloseButton_iconColor: "#000000", 94 | popupCloseButton_borderRadius: "0px", 95 | popupCloseButton_margin: "0px", 96 | popupCloseButton_action: { 97 | name: "close_popup", 98 | attrs: { 99 | onClick: 100 | "document.querySelector('.u-popup-container').style.display = 'none';", 101 | }, 102 | }, 103 | backgroundColor: "#e7e7e7", 104 | linkStyle: { 105 | body: true, 106 | linkColor: "#0000ee", 107 | linkHoverColor: "#0000ee", 108 | linkUnderline: true, 109 | linkHoverUnderline: true, 110 | }, 111 | _meta: { 112 | htmlID: "u_body", 113 | htmlClassNames: "u_body", 114 | }, 115 | }, 116 | }, 117 | schemaVersion: 16, 118 | }; 119 | -------------------------------------------------------------------------------- /src/middleware.ts: -------------------------------------------------------------------------------- 1 | import { authMiddleware } from "@clerk/nextjs"; 2 | import { NextRequest, NextResponse, NextFetchEvent } from "next/server"; 3 | 4 | // export function middleware(req: NextRequest, event: NextFetchEvent) { 5 | // // Create a response object for OPTIONS requests or a default response for others 6 | // let response = req.method === "OPTIONS" ? new NextResponse(null, { 7 | // status: 204, 8 | // headers: { 9 | // "Access-Control-Allow-Origin": "*", // Adjust as necessary 10 | // "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS", 11 | // "Access-Control-Allow-Headers": "Content-Type, Authorization", 12 | // }, 13 | // }) : NextResponse.next(); 14 | 15 | // // Ensure CORS headers are applied to all responses, not just OPTIONS 16 | // if (req.method !== "OPTIONS") { 17 | // response.headers.set("Access-Control-Allow-Origin", "*"); 18 | // response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS"); 19 | // response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization"); 20 | // } 21 | 22 | // return response; 23 | // } 24 | 25 | export default authMiddleware({ 26 | publicRoutes: ["/sign-in", "/sign-up", "/api/webhook", "/api/subscribe"], 27 | }); 28 | 29 | export const config = { 30 | matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"], 31 | }; 32 | -------------------------------------------------------------------------------- /src/models/email.model.tsx: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | const { Schema } = mongoose; 4 | 5 | const emailSchema = new Schema( 6 | { 7 | title: { 8 | type: String, 9 | }, 10 | content: { 11 | type: String, 12 | }, 13 | newsLetterOwnerId: { 14 | type: String, 15 | }, 16 | }, 17 | { timestamps: true } 18 | ); 19 | 20 | const Email = mongoose.models.Emails || mongoose.model("Emails", emailSchema); 21 | export default Email; 22 | -------------------------------------------------------------------------------- /src/models/membership.model.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | const { Schema } = mongoose; 4 | 5 | const membershipSchema = new Schema( 6 | { 7 | userId: { 8 | type: String, 9 | }, 10 | stripeCustomerId: { 11 | type: String, 12 | }, 13 | plan: { 14 | type: String, 15 | }, 16 | }, 17 | { timestamps: true } 18 | ); 19 | 20 | const Membership = mongoose.models.Memberships || mongoose.model("Memberships", membershipSchema); 21 | export default Membership; 22 | -------------------------------------------------------------------------------- /src/models/subscriber.model.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | 3 | const { Schema } = mongoose; 4 | 5 | const subscriberShema = new Schema( 6 | { 7 | email: { 8 | type: String, 9 | }, 10 | newsLetterOwnerId: { 11 | type: String, 12 | }, 13 | source: { 14 | type: String, 15 | }, 16 | status: { 17 | type: String, 18 | }, 19 | }, 20 | { timestamps: true } 21 | ); 22 | 23 | const Subscriber = 24 | mongoose.models.Subscribers || mongoose.model("Subscribers", subscriberShema); 25 | 26 | export default Subscriber; 27 | -------------------------------------------------------------------------------- /src/modules/dashboard/dashboard.tsx: -------------------------------------------------------------------------------- 1 | import Main from "./elements/main/main"; 2 | 3 | const Dashboard = () => { 4 | return ( 5 | 6 | ); 7 | }; 8 | 9 | export default Dashboard; 10 | -------------------------------------------------------------------------------- /src/modules/dashboard/elements/main/main.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useUser } from "@clerk/nextjs"; 3 | 4 | import DashboardOverViewCard from "@/shared/components/cards/overview.card"; 5 | import SubscribersChart from "@/shared/components/charts/subscribers.chart"; 6 | import { Button } from "@nextui-org/react"; 7 | import { ICONS } from "@/shared/utils/icons"; 8 | import { useState } from "react"; 9 | import toast from "react-hot-toast"; 10 | import Link from "next/link"; 11 | 12 | const Main = () => { 13 | const { user } = useUser(); 14 | const [copied, setCopied] = useState(false); 15 | 16 | const handleCopyClick = () => { 17 | const smallText = document.querySelector(".copy-text") as HTMLElement; 18 | if (smallText) { 19 | const textToCopy = smallText.innerText; 20 | navigator.clipboard.writeText(textToCopy).then(() => { 21 | setCopied(true); 22 | toast.success("Copied"); 23 | setTimeout(() => { 24 | setCopied(false); 25 | }, 2000); 26 | }); 27 | } 28 | }; 29 | 30 | return ( 31 |
36 | Here's how your publication is doing 37 |
38 |87 | Learn how to get started on becodemy and utilize all our features, 88 | directly from the becodemy team. 89 |
90 |11 | Add in your own website. No complex integrations. 12 |
13 |26 | Warning: A writing experience unlike anything you‘ve ever 27 | experienced - proceed with caution. 28 |
29 |Simple. Predictable. Built for you.
18 |No commitment
46 |What's included...
49 |{i.title}
54 |61 | 30-day free trial of Scale features, then free forever 62 |
63 |Billed {active}
90 |Everything in Launch, plus...
93 |{i.title}
98 |116 | 30-day free trial of Scale features, then $ 117 | {active === "Monthly" ? "42" : "49"}/mo 118 |
119 |Billed {active}
146 |Everything in Grow, plus...
149 |{i.title}
154 |172 | 30-day free trial of Scale features, then $ 173 | {active === "Monthly" ? "99" : "84"}/mo 174 |
175 |Shows all active subscribers
71 |95 | © 2024 Becodemy, Inc. All rights reserved. 96 |
97 | > 98 | )} 99 | > 100 | ); 101 | }; 102 | 103 | export default DashboardItems; 104 | -------------------------------------------------------------------------------- /src/shared/widgets/dashboard/sidebar/dashboard.sidebar.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { ICONS } from "@/shared/utils/icons"; 4 | import { useUser } from "@clerk/nextjs"; 5 | import DashboardItems from "./dashboard.items"; 6 | import UserPlan from "./user.plan"; 7 | 8 | const DashboardSideBar = () => { 9 | const { user } = useUser(); 10 | 11 | return ( 12 |