Skip to content

Commit e27b1ee

Browse files
authored
Merge pull request #90 from codeunia-dev/feat/profilepageandmembercard
feat: add profile settings page and membership card functionality
2 parents bf235f7 + f14f838 commit e27b1ee

11 files changed

Lines changed: 1372 additions & 1 deletion

File tree

app/protected/page.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { redirect } from "next/navigation";
22
import { createClient } from "@/lib/supabase/server";
3-
import { Sparkles, Rocket, Shield, User } from "lucide-react";
3+
import { Sparkles, Rocket, Shield, User, Settings } from "lucide-react";
44
import Link from "next/link";
5+
import { Button } from "@/components/ui/button";
6+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
7+
import MembershipCard from "@/components/MembershipCard";
58
export default async function ProtectedPage() {
69
const supabase = await createClient();
710

@@ -61,6 +64,11 @@ export default async function ProtectedPage() {
6164
</div>
6265
</div>
6366

67+
{/* Membership Card Section */}
68+
<div className="flex justify-center my-8">
69+
<MembershipCard uid={data.user.id} />
70+
</div>
71+
6472

6573
<div className="relative group">
6674
<div className="absolute -inset-1 bg-gradient-to-r from-yellow-400 via-orange-500 to-red-500 rounded-2xl blur opacity-25 group-hover:opacity-40 transition duration-1000 group-hover:duration-200"></div>
@@ -96,6 +104,27 @@ export default async function ProtectedPage() {
96104
</div>
97105

98106

107+
{/* Profile Settings Card */}
108+
<Card className="mb-8">
109+
<CardHeader>
110+
<CardTitle className="flex items-center gap-2">
111+
<Settings className="h-5 w-5" />
112+
Customize Your Profile
113+
</CardTitle>
114+
<CardDescription>
115+
Add your information, social links, and customize how others see you
116+
</CardDescription>
117+
</CardHeader>
118+
<CardContent>
119+
<Button asChild className="w-full sm:w-auto">
120+
<Link href="/protected/profile" className="flex items-center gap-2">
121+
<Settings className="h-4 w-4" />
122+
Manage Profile
123+
</Link>
124+
</Button>
125+
</CardContent>
126+
</Card>
127+
99128
<div className="grid md:grid-cols-3 gap-6 mt-12">
100129
<div className="group p-6 bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 hover:shadow-lg hover:border-blue-300 dark:hover:border-blue-600 transition-all duration-300">
101130
<div className="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-lg flex items-center justify-center mb-4 group-hover:scale-110 transition-transform">

app/protected/profile/page.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { redirect } from "next/navigation";
2+
import { createClient } from "@/lib/supabase/server";
3+
import Link from "next/link";
4+
import { ArrowLeft } from "lucide-react";
5+
import { ProfileSettings } from "@/components/profile/ProfileSettings";
6+
7+
export default async function ProfilePage() {
8+
const supabase = await createClient();
9+
10+
const { data, error } = await supabase.auth.getUser();
11+
if (error || !data?.user) {
12+
redirect("/auth/signin");
13+
}
14+
15+
return (
16+
<div className="min-h-screen bg-gradient-to-br from-background via-background to-muted/10">
17+
{/* Header */}
18+
<div className="bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm border-b border-border/50 sticky top-0 z-10">
19+
<div className="max-w-4xl mx-auto px-6 py-4">
20+
<div className="flex items-center gap-4">
21+
<Link
22+
href="/protected"
23+
className="inline-flex items-center gap-2 px-3 py-2 rounded-lg bg-muted hover:bg-muted/80 transition-colors"
24+
>
25+
<ArrowLeft className="h-4 w-4" />
26+
Back to Dashboard
27+
</Link>
28+
<h1 className="text-2xl font-bold">Profile Settings</h1>
29+
</div>
30+
</div>
31+
</div>
32+
33+
{/* Profile Settings Component */}
34+
<ProfileSettings />
35+
</div>
36+
);
37+
}

components/MembershipCard.tsx

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
"use client";
2+
3+
import React, { useRef } from 'react';
4+
import jsPDF from 'jspdf';
5+
import html2canvas from 'html2canvas';
6+
7+
interface MembershipCardProps {
8+
uid: string;
9+
}
10+
11+
const MembershipCard: React.FC<MembershipCardProps> = ({ uid }) => {
12+
const cardRef = useRef<HTMLDivElement>(null);
13+
const pdfContentRef = useRef<HTMLDivElement>(null);
14+
const memberId = `CU-${uid.slice(-4)}`;
15+
16+
const handleDownload = async () => {
17+
if (pdfContentRef.current) {
18+
const canvas = await html2canvas(pdfContentRef.current, {
19+
scale: 2,
20+
useCORS: true,
21+
allowTaint: true,
22+
backgroundColor: '#ffffff'
23+
});
24+
25+
const imgData = canvas.toDataURL('image/png');
26+
const pdf = new jsPDF({
27+
orientation: 'portrait',
28+
unit: 'mm',
29+
format: 'a4'
30+
});
31+
32+
const imgWidth = 210;
33+
const imgHeight = (canvas.height * imgWidth) / canvas.width;
34+
35+
pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight);
36+
pdf.save(`${memberId}-membership-card.pdf`);
37+
}
38+
};
39+
40+
return (
41+
<>
42+
{/* Hidden PDF Content - Only visible when generating PDF */}
43+
<div
44+
ref={pdfContentRef}
45+
className="fixed -left-[9999px] top-0 bg-white"
46+
style={{ width: '210mm', minHeight: '297mm', padding: '20mm' }}
47+
>
48+
{/* PDF Header */}
49+
<div className="text-center mb-8">
50+
<div className="flex items-center justify-center mb-4">
51+
<div className="w-12 h-12 bg-purple-600 rounded-full flex items-center justify-center mr-4">
52+
<div className="w-4 h-4 bg-white rounded-full"></div>
53+
</div>
54+
<h1 className="text-4xl font-bold text-purple-600">CodeUnia</h1>
55+
</div>
56+
<p className="text-xl text-blue-600 font-semibold mb-2">CodeUnia members achieve great things</p>
57+
</div>
58+
59+
{/* Thank You Section */}
60+
<div className="mb-8">
61+
<h2 className="text-2xl font-bold text-blue-600 mb-2">THANK YOU</h2>
62+
<p className="text-sm text-yellow-600 font-semibold mb-4">FOR YOUR MEMBERSHIP</p>
63+
64+
<p className="text-sm text-gray-700 mb-4">
65+
You are a member of the CodeUnia Community.
66+
</p>
67+
68+
<p className="text-sm text-gray-700 mb-6">
69+
Below is a digital version of your membership card for easy access to your membership
70+
information. You can also access this in your CodeUnia Profile or in the CodeUnia app anytime!
71+
</p>
72+
</div>
73+
74+
{/* Benefits Grid */}
75+
<div className="grid grid-cols-2 gap-6 mb-8 text-sm">
76+
<div>
77+
<h3 className="font-bold text-blue-600 mb-2">Local CodeUnia Community</h3>
78+
<p className="text-gray-700 mb-4">
79+
Get involved with colleagues at your local CodeUnia Community,
80+
who can help connect you to professionals who can advance your goals.
81+
</p>
82+
83+
<h4 className="font-bold text-blue-600 mb-1">Technical Publications</h4>
84+
<p className="text-gray-700 mb-4">
85+
Take advantage of discounts and access to cutting-edge journals, magazines, and
86+
digital publications.
87+
</p>
88+
89+
<h4 className="font-bold text-blue-600 mb-1">Professional Network</h4>
90+
<p className="text-gray-700">
91+
Build a professional network from the wealth of university expertise and connections
92+
found within CodeUnia.
93+
</p>
94+
</div>
95+
96+
<div>
97+
<h3 className="font-bold text-blue-600 mb-2">Local CodeUnia Student Branch</h3>
98+
<p className="text-gray-700 mb-4">
99+
Join and enjoy exciting technical competitions, expert speakers,
100+
professional networking, and colleagues for life.
101+
</p>
102+
103+
<h4 className="font-bold text-blue-600 mb-1">Career Opportunities</h4>
104+
<p className="text-gray-700 mb-4">
105+
Drive your career goals forward with online learning,
106+
job listings, a consultants network, and more!
107+
</p>
108+
109+
<h4 className="font-bold text-blue-600 mb-1">Local Activities</h4>
110+
<p className="text-gray-700">
111+
Through your local CodeUnia community, events and conferences -
112+
there are many ways to become involved.
113+
</p>
114+
</div>
115+
</div>
116+
117+
{/* Membership Card in PDF */}
118+
<div className="flex justify-center mb-8">
119+
<div className="bg-white rounded-lg shadow-lg border border-gray-300" style={{ width: '420px', height: '250px' }}>
120+
<div className="flex h-full">
121+
{/* Left Section - Member Info */}
122+
<div className="flex-1 p-4 bg-gradient-to-br from-gray-50 to-white rounded-l-lg">
123+
{/* Student Member Badge */}
124+
<div className="mb-3">
125+
<span className="inline-block px-3 py-1 bg-blue-100 text-blue-800 text-xs font-bold rounded-full border border-blue-200">
126+
STUDENT MEMBER
127+
</span>
128+
</div>
129+
130+
{/* CodeUnia Title */}
131+
<div className="mb-4">
132+
<h1 className="text-2xl font-black text-gray-900 tracking-tight">
133+
code unia
134+
</h1>
135+
</div>
136+
137+
{/* Member ID */}
138+
<div className="mb-3">
139+
<div className="text-sm text-gray-600">Member ID:
140+
<span className="text-blue-600 font-mono font-bold">{memberId}</span>
141+
</div>
142+
</div>
143+
144+
{/* Status and Year */}
145+
<div className="flex items-center gap-3 mb-4">
146+
<span className="inline-block px-3 py-1 bg-green-100 text-green-800 text-xs font-semibold rounded border border-green-200">
147+
Active Member
148+
</span>
149+
<span className="inline-block px-3 py-1 bg-yellow-100 text-yellow-800 text-xs font-semibold rounded border border-yellow-200">
150+
2025
151+
</span>
152+
</div>
153+
154+
{/* Validity Info */}
155+
<div className="text-xs text-gray-600">
156+
<div>Valued Codeunia Member for 1 Year</div>
157+
<div className="font-semibold">Valid through 31 December 2025</div>
158+
</div>
159+
</div>
160+
161+
{/* Right Section - Purple Background with Logo */}
162+
<div className="w-36 bg-gradient-to-br from-purple-600 to-purple-800 p-4 flex flex-col items-center justify-center text-white relative rounded-r-lg">
163+
{/* Logo Circle */}
164+
<div className="w-12 h-12 bg-white rounded-full flex items-center justify-center mb-3 shadow-lg">
165+
<div className="w-2 h-2 bg-blue-500 rounded-full"></div>
166+
</div>
167+
168+
{/* CodeUnia Text */}
169+
<div className="text-center mb-4">
170+
<h2 className="text-sm font-bold tracking-wide">CodeUnia</h2>
171+
<p className="text-xs text-purple-200 mt-1">Empowering Coders</p>
172+
</div>
173+
174+
{/* Footer */}
175+
<div className="absolute bottom-3 left-2 right-2 text-center">
176+
<div className="text-xs text-purple-200 mb-1">Powered by Codeunia</div>
177+
<div className="text-xs text-purple-300">support@codeunia.com</div>
178+
</div>
179+
</div>
180+
</div>
181+
</div>
182+
</div>
183+
184+
{/* Footer Info */}
185+
<div className="text-center text-xs text-gray-600 mt-8">
186+
<p className="mb-2">
187+
<span className="font-semibold">Make the Most of Your Membership.</span> Learn about these and all CodeUnia member benefits at{' '}
188+
<span className="text-blue-600 font-semibold">codeunia.com/benefits</span>
189+
</p>
190+
</div>
191+
</div>
192+
193+
{/* Visible Card for Display */}
194+
<div className="flex flex-col items-center p-8">
195+
{/* Main Card */}
196+
<div className="relative transform hover:scale-[1.02] transition-all duration-300 ease-out">
197+
<div
198+
ref={cardRef}
199+
className="flex bg-white rounded-3xl shadow-2xl border border-gray-200 overflow-hidden w-[500px] h-[300px]"
200+
>
201+
{/* Left Section - Member Info */}
202+
<div className="flex-1 p-6 bg-gradient-to-br from-gray-50 to-white">
203+
{/* Student Member Badge */}
204+
<div className="mb-4">
205+
<span className="inline-block px-4 py-1 bg-blue-100 text-blue-800 text-xs font-bold rounded-full border border-blue-200">
206+
STUDENT MEMBER
207+
</span>
208+
</div>
209+
210+
{/* CodeUnia Title */}
211+
<div className="mb-6">
212+
<h1 className="text-3xl font-black text-gray-900 tracking-tight">
213+
code unia
214+
</h1>
215+
</div>
216+
217+
{/* Member ID */}
218+
<div className="mb-4">
219+
<div className="text-sm text-gray-600 mb-1">Member ID:
220+
<span className="text-blue-600 font-mono font-bold">{memberId}</span>
221+
</div>
222+
</div>
223+
224+
{/* Status and Year */}
225+
<div className="flex items-center gap-4 mb-6">
226+
<span className="inline-block px-3 py-1 bg-green-100 text-green-800 text-xs font-semibold rounded-md border border-green-200">
227+
Active Member
228+
</span>
229+
<span className="inline-block px-3 py-1 bg-yellow-100 text-yellow-800 text-xs font-semibold rounded-md border border-yellow-200">
230+
2025
231+
</span>
232+
</div>
233+
234+
{/* Validity Info */}
235+
<div className="text-xs text-gray-600 mb-2">
236+
<div>Valued Codeunia Member for 1 Year</div>
237+
<div className="font-semibold">Valid through 31 December 2025</div>
238+
</div>
239+
</div>
240+
241+
{/* Right Section - Purple Background with Logo */}
242+
<div className="w-48 bg-gradient-to-br from-purple-600 to-purple-800 p-6 flex flex-col items-center justify-center text-white relative">
243+
{/* Logo Circle */}
244+
<div className="w-16 h-16 bg-white rounded-full flex items-center justify-center mb-4 shadow-lg">
245+
<div className="w-3 h-3 bg-blue-500 rounded-full"></div>
246+
</div>
247+
248+
{/* CodeUnia Text */}
249+
<div className="text-center mb-4">
250+
<h2 className="text-xl font-bold tracking-wide">CodeUnia</h2>
251+
<p className="text-sm text-purple-200 mt-1">Empowering Coders</p>
252+
</div>
253+
254+
{/* Footer */}
255+
<div className="absolute bottom-4 left-4 right-4 text-center">
256+
<div className="text-xs text-purple-200 mb-1">Powered by Codeunia</div>
257+
<div className="text-xs text-purple-300">support@codeunia.com</div>
258+
</div>
259+
</div>
260+
</div>
261+
</div>
262+
263+
{/* Download Button */}
264+
<div className="mt-8">
265+
<button
266+
onClick={handleDownload}
267+
className="px-6 py-3 bg-gradient-to-r from-purple-600 to-blue-600 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-300"
268+
>
269+
<div className="flex items-center gap-2">
270+
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
271+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
272+
</svg>
273+
Download PDF Card
274+
</div>
275+
</button>
276+
</div>
277+
</div>
278+
</>
279+
);
280+
};
281+
282+
export default MembershipCard;

0 commit comments

Comments
 (0)