diff --git a/packages/db/src/schemas/index.ts b/packages/db/src/schemas/index.ts
index 78be0cf..88deb89 100644
--- a/packages/db/src/schemas/index.ts
+++ b/packages/db/src/schemas/index.ts
@@ -1,6 +1,6 @@
+// Export all schemas, avoiding conflicts
export * from "./auth";
-export * from "./users";
-export * from "./members";
+export * from "./members"; // This includes userProfiles
export * from "./hackathons";
export * from "./admins";
-export * from "./events";
\ No newline at end of file
+export * from "./events";
diff --git a/packages/db/src/schemas/users.ts b/packages/db/src/schemas/users.ts
deleted file mode 100644
index a02f4a7..0000000
--- a/packages/db/src/schemas/users.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
-
-export const userProfiles = pgTable("user_profile", {
- id: uuid("id").defaultRandom().primaryKey(),
- userId: text("user_id")
- .notNull()
- .references(() => users.id, { onDelete: "cascade" }),
- bio: text("bio"),
- website: text("website"),
- location: text("location"),
- createdAt: timestamp("created_at").defaultNow().notNull(),
- updatedAt: timestamp("updated_at").defaultNow().notNull(),
-});
-
-import { users } from "./auth";
\ No newline at end of file
diff --git a/sites/portal/src/app/dashboard/page.tsx b/sites/portal/src/app/dashboard/page.tsx
index 228d2f1..ac6efc0 100644
--- a/sites/portal/src/app/dashboard/page.tsx
+++ b/sites/portal/src/app/dashboard/page.tsx
@@ -65,18 +65,68 @@ export default function Dashboard() {
-
+
- {editTab === 'basic' && userData && }
+ {editTab === 'basic' && userData && (
+
+
+
+ {/* Guest Profile Editor for interests/skills */}
+ {!memberStatus?.isMember && (
+
+
+
💡 Limited Profile Access
+
+ As a guest, you can edit basic info. To unlock advanced member features (academic info, detailed portfolio), please register as a member.
+
+
+
+
+ )}
+
+ )}
+
{editTab === 'member' && (
- memberStatus?.isMember ? : Membership_Required_For_Advanced_Logs
+ memberStatus?.isMember ? (
+
+ ) : (
+
+
🔒
+
Members_Only_Section
+
+ Advanced member logs include academic records, detailed skill tracking, and official membership credentials. Register to unlock full access.
+
+
+
+ )
)}
@@ -132,7 +182,7 @@ export default function Dashboard() {
"{userData?.bio || "No public bio transmission found."}"
-
+
@@ -142,9 +192,9 @@ export default function Dashboard() {
/Academic_Logs
-
INSTITUTION: {memberData?.school}
-
PROGRAM: {memberData?.major}
-
CYCLE_END: {memberData?.graduationYear}
+
INSTITUTION: {memberData?.school || 'N/A'}
+
PROGRAM: {memberData?.major || 'N/A'}
+
CYCLE_END: {memberData?.graduationYear || 'N/A'}
@@ -152,13 +202,31 @@ export default function Dashboard() {
{memberData?.githubUrl &&
GITHUB}
{memberData?.linkedinUrl &&
LINKEDIN}
+ {memberData?.portfolioUrl &&
PORTFOLIO}
+
+
+
+
/Skills_&_Interests
+
+ {memberData?.skills?.map((skill: string, i: number) => (
+ {skill}
+ ))}
+ {memberData?.interests?.map((interest: string, i: number) => (
+ {interest}
+ ))}
) : (
-
+
Advanced_Dossier_Encrypted
Complete Membership Registration to Unlock Verified Logs
+
)}
@@ -175,11 +243,25 @@ export default function Dashboard() {
) : (
ERR: Unregistered_Node
+
Club operations require active membership. Register to access events, check-ins, and member benefits.
)}
)}
+
+ {/* --- HACKLYTICS MODE --- */}
+ {mode === 'HACKLYTICS' && (
+
+
+
Hackathon_Portal_Active
+
Browse hackathons, register for events, and submit projects. All users (members and guests) can participate.
+
+
+
+ )}
diff --git a/sites/portal/src/components/profile/ProfileForm.tsx b/sites/portal/src/components/profile/ProfileForm.tsx
index f7205d5..c2ff514 100644
--- a/sites/portal/src/components/profile/ProfileForm.tsx
+++ b/sites/portal/src/components/profile/ProfileForm.tsx
@@ -2,54 +2,150 @@
import { useState } from 'react';
import { trpc } from '@/lib/trpc';
-import Image from 'next/image';
+import { useRouter } from 'next/navigation';
-export default function ProfileForm({ user }: { user: { name?: string | null; image?: string | null } }) {
+interface ProfileFormProps {
+ user: {
+ id: string;
+ name?: string | null;
+ email: string;
+ image?: string | null;
+ bio?: string | null;
+ };
+}
+
+export default function ProfileForm({ user }: ProfileFormProps) {
+ const router = useRouter();
const utils = trpc.useUtils();
- const [name, setName] = useState(user.name || '');
- const [imageUrl, setImageUrl] = useState(user.image || '');
+
+ const [formData, setFormData] = useState({
+ name: user.name || '',
+ image: user.image || '',
+ bio: user.bio || '',
+ });
+
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [message, setMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null);
const updateProfile = trpc.user.updateProfile.useMutation({
- onSuccess: () => utils.user.me.invalidate(),
+ onSuccess: () => {
+ setMessage({ type: 'success', text: 'Profile updated successfully' });
+ utils.user.me.invalidate();
+ setIsSubmitting(false);
+
+ setTimeout(() => setMessage(null), 3000);
+ },
+ onError: (error) => {
+ setMessage({ type: 'error', text: error.message || 'Failed to update profile' });
+ setIsSubmitting(false);
+ },
});
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault();
- updateProfile.mutate({ name, image: imageUrl });
+ const handleSubmit = () => {
+ setIsSubmitting(true);
+ setMessage(null);
+
+ updateProfile.mutate({
+ name: formData.name || undefined,
+ image: formData.image || undefined,
+ bio: formData.bio || undefined,
+ });
};
return (
-