Skip to content

Commit

Permalink
[CIT-19] Update user profile (#48)
Browse files Browse the repository at this point in the history
* edit client and server components for user profile

* user profile successfully updating

* bug fixes

* CIT-19: fix refresh, text boxes, api, profile display

* Trigger build

* CIT-19: bugfix

Co-authored-by: Ishaan Upadhyay <[email protected]>

* Trigger build

* add pricing

* [CIT-19] Visual improvements

* [CIT-19] Bugfix

---------

Co-authored-by: Daniel <[email protected]>
Co-authored-by: Ishaan <[email protected]>
Co-authored-by: Ishaan Upadhyay <[email protected]>
Co-authored-by: Ishaan Upadhyay <[email protected]>
  • Loading branch information
5 people authored Aug 10, 2023
1 parent cca3075 commit 4ebec0d
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 65 deletions.
2 changes: 1 addition & 1 deletion citrus/app/(users)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export default async function RootLayout({
<a href="/experiences">Experiences</a>
</li>
<li className='flex-1'>
<a href="/about">About</a>
<a href="/profile">Profile</a>
</li>
<li className='flex-1'>
<a href="/groups">Chats</a>
Expand Down
126 changes: 126 additions & 0 deletions citrus/app/(users)/profile/UserProfileClient.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
"use client";
import { FormEvent, useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from "next/navigation";
import '@/lib/patch'

async function updateUserProfile(data: any) {
try {
const res = await fetch(`/api/users`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

if (res.ok) {
console.log('Profile updated successfully!');
} else {
console.error('Failed to update profile:', res.status);
}
} catch (error) {
console.error('An error occurred while updating the profile:', error);
}
}

export default function UserProfileClient() {
const { data: session } = useSession();

const [phoneNumber, setPhoneNumber] = useState('');
const [instagram, setInstagram] = useState('');
const [facebook, setFacebook] = useState('');
const [interest, setInterest] = useState(''); // Separate state for individual interest
const [interests, setInterests] = useState<string[]>([]); // State to store all interests

const handleInterestChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInterest(e.target.value);
};

const handleAddInterest = () => {
if (interest.trim() !== '') {
setInterests([...interests, interest.trim()]); // Add the new interest to the interests array
setInterest(''); // Clear the individual interest state
}
};

const handleRemoveInterest = (index: number) => {
const updatedInterests = interests.filter((_, i) => i !== index);
setInterests(updatedInterests);
};

const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();

// Assuming you have a user ID in userData
const updatedData = {
username: session?.user?.name,
phone_number: phoneNumber == "" ? undefined : phoneNumber,
instagram: instagram == "" ? undefined : instagram,
facebook: facebook == "" ? undefined : facebook,
interests: interests.length == 0 ? undefined : interests, // Use the interests array in the updated data
};

await updateUserProfile(updatedData);
router.refresh();
};

const router = useRouter();

return (
<>
<h1 className='text-xl font-extrabold'>
Edit Profile
</h1>
<form onSubmit={handleSubmit} className="flex-col content-center gap-2.5 text-center">
<div>
<label>
Phone Number
</label>
<br />
<input type="text" value={phoneNumber} className="mr-2 px-4 py-2 border border-gray-300 rounded-md text-black"
onChange={(e) => setPhoneNumber(e.target.value)} />
</div>
<div>
<label>
Instagram
</label>
<br />
<input type="text" value={instagram} className="mr-2 px-4 py-2 border border-gray-300 rounded-md text-black"
onChange={(e) => setInstagram(e.target.value)} />
</div>
<div>
<label>
Facebook
<br />
</label>
<input type="text" value={facebook} className="mr-2 px-4 py-2 border border-gray-300 rounded-md text-black"
onChange={(e) => setFacebook(e.target.value)} />
</div>
<div>
<label>
Interests
</label>
<div>
<input type="text" value={interest} className="py-2 border border-gray-300 rounded-md text-black"
onChange={handleInterestChange} />
<button type="button" className="border p-3 rounded-lg bg-blue-900" onClick={handleAddInterest}>
Add
</button>
</div>
</div>
<ul>
{interests.map((item, index) => (
<li key={index}>
{item}{' '}
<button type="button" className="border p-4 rounded-lg bg-blue-900" onClick={() => handleRemoveInterest(index)}>
Remove
</button>
</li>
))}
</ul>
<button className="border p-4 mt-8 rounded-lg bg-blue-900" type="submit">Update Profile</button>
</form >
</>
);
}
26 changes: 26 additions & 0 deletions citrus/app/(users)/profile/UserProfileServer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
import '@/lib/patch'

export default async function UserProfileServer(){

const session = await getServerSession(authOptions);

if(!session) return <p>You&apos;re not signed in.</p>

const res = await fetch(process.env.BASE_API_URL + `api/users/${session.user?.name}`);
const userData = await res.json();

if (!userData) return <p>Loading user data...</p>;

return (
<div className="text-2xl">
<p>Name: {userData.username}</p>
<p>Email: {userData.email}</p>
<p>Phone Number: {userData.phone_number}</p>
<p>Instagram: {userData.instagram}</p>
<p>Facebook: {userData.facebook}</p>
<p>Interests: {userData.interests && userData.interests.length > 0 ? userData.interests.join(", ") : ""}</p>
</div>
);
}
32 changes: 32 additions & 0 deletions citrus/app/(users)/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// App.tsx
import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
import { useState, useEffect } from 'react';
import UserProfileServer from './UserProfileServer';
import UserProfileClient from './UserProfileClient';
import styles from './profile.module.css';

export default async function Page() {

const session = await getServerSession(authOptions);
if (!session)
return <p>You&apos;re not signed in.</p>;

return (

<div className={styles["custom-background"]} style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100vh", flexDirection: "column" }}>
{/* Big Header */}
<h1 className="font-extrabold text-6xl">User Profile</h1>

<div style={{ display: "flex" }}>
<div className={styles["custom-box"]}>
{/* @ts-expect-error Server Component */}
<UserProfileServer />
</div>
<div className={styles["custom-box"]}>
<UserProfileClient />
</div>
</div>
</div>
);
}
81 changes: 81 additions & 0 deletions citrus/app/(users)/profile/profile.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.custom-heading {
font-size: 40px;
}

.custom-background {
background-color: rgb(0, 0, 0);
}

.custom-avatar {
width: 100px;
height: 100px;
display: flex;
align-items: center; /* Vertically align the avatar */
justify-content: center; /* Horizontally align the avatar */
}

.custom-input {
border: 1px solid #ccc;
padding: 0.5rem;
border-radius: 4px;
margin-bottom: 1rem;
color: black;
width: 300px;
}
.custom-box {
border: 1px solid #ccc;
padding: 3rem;
border-radius: 4px;
margin-bottom: 1rem;
margin: 20px; /* Add a margin of 20px around the custom-box */
background-color: rgb(37, 99, 235);
display: flex; /* Display the container as a flex container */
flex-direction: column; /* Stack the content vertically */
align-items: center; /* Center the content horizontally */
justify-content: center; /* Center the content vertically */
/* Add the following CSS properties to prevent horizontal growth */
flex-wrap: wrap; /* Allow content to wrap to the next line */
max-width: 100%; /* Limit the maximum width of the container */

/* height: 100%; */
}
.custom-acc-button {
border: 1px solid #ccc;
padding: 0.5rem;
border-radius: 4px;
}

.custom-box-content {
flex-grow: 1; /* Ensure the content expands to fill the box */
}

.custom-box-footer {
margin-top: 1rem; /* Add some space above the footer */
}

.custom-avatar-container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}

.custombox2{
border: 1px solid #ccc;
padding: 1rem;
border-radius: 50px;
margin-bottom: 1rem;
margin: 20px; /* Add a margin of 20px around the custom-box */

display: flex; /* Display the container as a flex container */
flex-direction: column; /* Stack the content vertically */
align-items: center; /* Center the content horizontally */
justify-content: center; /* Center the content vertically */
/* Add the following CSS properties to prevent horizontal growth */
flex-wrap: wrap; /* Allow content to wrap to the next line */
max-width: 100%; /* Limit the maximum width of the container */
}

.blackText {
color: black;
}
9 changes: 5 additions & 4 deletions citrus/app/api/users/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as db from '@/lib/db'
import { NextResponse } from 'next/server';
import '@/lib/patch'

const prisma = db.getClient();

Expand All @@ -19,10 +20,8 @@ const prisma = db.getClient();
* "username": "sampleUsername",
* "email": "[email protected]",
* "phone_number": "16471234567",
* "socials": [
* "https://www.instagram.com/sampleUsername/",
* "https://www.facebook.com/sampleUsername/"
* ],
* "instagram": "https://www.instagram.com/sampleUsername/",
* "facebook": "https://www.facebook.com/sampleUsername/"
* "premium": true,
* "experiences": []
* }
Expand All @@ -32,10 +31,12 @@ export async function GET(request: Request, { params }: { params: { id: string }

let select = {
username: true,
phone_number: true,
email: true,
instagram: true,
facebook: true,
premium: true,
interests: true,
experiences: true
};

Expand Down
26 changes: 17 additions & 9 deletions citrus/app/api/users/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ schema
* @apiSuccess {String} users.username The username of the user
* @apiSuccess {String} users.email The email of the user
* @apiSuccess {String} users.phone_number The phone number of the user
* @apiSuccess {String[]} users.socials The social media links of the user
* @apiSuccess {String} users.instagram The instagram link of the user
* @apiSuccess {String} users.facebook The facebook link of the user
* @apiSuccess {Boolean} users.premium Whether the user is a premium user
*
* @apiSuccessExample Success-Response:
Expand All @@ -48,10 +50,8 @@ schema
* "username": "sampleUsername",
* "email": "[email protected]",
* "phone_number": "16471234567",
* "socials": [
* "https://www.instagram.com/sampleUsername/",
* "https://www.facebook.com/sampleUsername/"
* ],
* "instagram": "https://www.instagram.com/sampleUsername/",
* "facebook": "https://www.facebook.com/sampleUsername/"
* "premium": true
* }
* ]
Expand Down Expand Up @@ -108,9 +108,11 @@ schema
username: true,
email: true,
premium: true,
phone_number: true,
instagram: true,
facebook: true,
experiences: true
experiences: true,
interests: true,
};

try {
Expand Down Expand Up @@ -208,7 +210,9 @@ schema
* @apiParam {String} email The email of the user
* @apiParam {Boolean} premium Whether the user is a premium user
* @apiParam {String} phone_number The phone number of the user
* @apiParam {String[]} socials The social media links of the user
* @apiParam {String} instagram The instagram link of the user
* @apiParam {String} facebook The facebook link of the user
*
* @apiSuccess {String} username The username of the user
* @apiSuccess {String} message The message indicating the success of the request
Expand All @@ -235,7 +239,9 @@ export async function PUT(request: Request) {
const email = body.email;
const premium = body.premium;
const phone_number = body.phone_number;
//const socials = body.socials;
const instagram = body.instagram;
const facebook = body.facebook;
const interests = body.interests;

if (password !== undefined) {
if (!schema.validate(password)) {
Expand All @@ -251,7 +257,9 @@ export async function PUT(request: Request) {
email: email,
premium: premium,
phone_number: phone_number,
//socials: socials
instagram: instagram,
facebook: facebook,
interests: interests,
}

try {
Expand Down
Loading

1 comment on commit 4ebec0d

@vercel
Copy link

@vercel vercel bot commented on 4ebec0d Aug 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aajaleel is attempting to deploy a commit to a Personal Account on Vercel that is not owned by them.

In order for the commit to be deployed, @aajaleel must be granted access to the connected Vercel project.

If you're the owner of the Personal Account, transfer the project to a Vercel Team and start collaborating, or learn more.

Please sign in to comment.