Skip to content

Commit

Permalink
added edit posts, search posts
Browse files Browse the repository at this point in the history
  • Loading branch information
tomyRomero committed Feb 29, 2024
1 parent 15c6139 commit bab329e
Show file tree
Hide file tree
Showing 45 changed files with 2,179 additions and 375 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
NEXT_PUBLIC_PUSHER_APP_KEY=

# for the sharing posts, input root link of site
NEXT_PUBLIC_LINK=
37 changes: 23 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,20 @@ Sparks is a full stack social media web app that is designed to help users disco

## <a name="features">🚀 Features</a>

- AI-powered post generation with various categories and the ability to delete ones you do not like if you are the author, AI image generation also included.
- Fully CRUD , creates, reads, updates, deletes all types of posts such as regular ones, comments and even AI generated ones.
- AI-powered post generation with various categories and the ability to edit/delete if you are the author, AI image generation also included.
- Categories:
- Movies and Novels (includes AI generated images if the User desires, optional)
- Artworks, Fashion , Photography , (These are all AI generated images)
- Haikus , Quote, Joke , Aphorism
prompts used are saved and can be viewed when the sparks logo of the post is clicked!
- Image Storage System: Cloud image storage powered by the cloud , allows all profile images, as well as profile posts and even AI generated images to be saved for future usage in a secure S3 bucket privately where only the developer can access them. Cache system included with local storage so images do not have to be fetched every single time.
- User profile management: Onboarding, Profile Edit
- User-to-user Messaging system: powered by Pusher(Web Sockets) for realtime updates, ability to leave messages on read, ability to see when a user is online in chat.
- Activity feed - and pagination for performance
- Activity feed - showing recent activity from other users to keep you engaged! Comes with pagination
- Home Page Feed Filtering - Allow users to filter out the type of posts they would like to see.
- Like comment and share functionality: Allows the liking of posts, no user can like a post more than once, users can unlike posts as well, everything is reflected in database, posts can have children posts (comments, which can be liked as well, authors can delete their comments as well) and they are all recursively structured where every comment has a parent ID, therefore comments can have comments of their own, providing a twitter-like comment structure, all powered by a SQL dynamic structure, users can share posts directly to other users in their inboxes by clicking the share button which will send a message with the posts' link.
- Search functionality, search for user profiles.
- Like comment and share functionality: Allows the liking of posts, no user can like a post more than once, users can unlike posts as well, everything is reflected in database, posts can have children posts (comments, which can be liked as well, authors can delete their comments as well) and they are all recursively structured where every comment has a parent ID, therefore comments can have comments of their own, providing a twitter-like comment structure, all powered by a SQL dynamic structure, users can share posts directly to other users in their inboxes by clicking the share button which will send a message with the posts' link. When a parent post is deleted all children post is recursively deleted as well!
- Search functionality, search for user profiles as well as posts by keywords
- Notification System: updates when user recieves new message or activity
- Profile Page: Profile page for users with posts they have made, comments they have made and posts they have liked, as well as the ability to message users from there or even edit your bio, and image if it is your profile.
- Database System: all changes are saved within the database so you can pick back up where you left off.
Expand Down Expand Up @@ -111,12 +113,18 @@ User interface and different functionalities of Sparks.
### Responsive
<img src="public/assets/sparks-moblie.png" alt="Screenshot of Home in Mobile">
<img src="public/assets/sparks-tablet.png" alt="Screenshot of Home in Tablet">
<img src="public/assets/sparks-prompt.png" alt="Screenshot of prompt in Phone">

### Create Studio
<img src="public/assets/sparks-studio.png" alt="Screenshot of User Profile">
<img src="public/assets/sparks-studio.png" alt="Screenshot of create studio">

### Sparks Post
<img src="public/assets/sparks-post.png" alt="Screenshot of Post">
<img src="public/assets/editSpark.png" alt="Screenshot of edit spark">
<img src="public/assets/editPost.png" alt="Screenshot of edit post">
<img src="public/assets/editComment.png" alt="Screenshot of edit comment">

### Search
<img src="public/assets/sparks-search.png" alt="Screenshot of search users">
<img src="public/assets/sparks-search-post.png" alt="Screenshot of search post">

### Share
<img src="public/assets/sparks-share.png" alt="Screenshot of Share Post">
Expand All @@ -131,6 +139,7 @@ User interface and different functionalities of Sparks.
### Profile
<img src="public/assets/sparks-profile.png" alt="Screenshot of User Profile">


# <a name="ai-post-examples">🤖 Sparks Examples [AI Posts] </a>
Below I tested all AI Post Categories with the same prompt , "apples in a warm summer's glow". These are the results.

Expand Down Expand Up @@ -172,25 +181,25 @@ Below I tested all AI Post Categories with the same prompt , "apples in a warm s
## Project Status

- **Literature Studio**: Works on the deployed version.
- **Story and Gallery Studio**: Currently functional only on localhost.
- **Story and Gallery Studio**: Currently functional only on localhost, sometimes on deployed if resources allow.

### Future Feature Idea for Contributions

This project is open source and contributors are welcomed
Future updates may be focused on these new features that I have in mind:

### 1. Post Search

Enhance user experience by implementing a post search functionality, allowing users to discover content more efficiently.

### 2. Followers List and Feed
### 1. Followers List and Feed

Introduce a followers list and feed, providing users with a personalized stream of content from accounts they follow.

### 3. Group Chats
### 2. Group Chats

Explore the implementation of group chats, fostering community interactions and group discussions.

### 3. Switch from Clerk to Next auth

Switch to a more independent form of auth, build from the ground up and allow vistors to browse posts even when not logged in

## <a name="acknowledgments"> 🙌 Acknowledgments</a>
Shout out to https://loading.io/ for all the icons provided
Shout out to https://unsplash.com/ for all the pictures that were not AI generated or user submitted
Expand Down
2 changes: 2 additions & 0 deletions app/(root)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getClerkUser } from "@/lib/actions/user.actions";
import Loading from "./loading";
import { updateOnlineStatus } from "@/lib/actions/chat.actions";
import { Metadata } from "next/types";
import { Toaster } from "@/components/ui/toaster";

const inter = Inter({ subsets: ["latin"] });

Expand Down Expand Up @@ -55,6 +56,7 @@ export default async function RootLayout({
<RightBar userid={userid}/>
</main>
<Bottombar userid={userid}/>
<Toaster />
</AppProvider>
</body>
</html>
Expand Down
3 changes: 3 additions & 0 deletions app/(root)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { fetchUser } from "@/lib/actions/user.actions";
import { redirect } from "next/navigation";
import Pagination from "@/components/shared/Pagination";
import FilterBox from "@/components/shared/FilterBox";
import SearchButton from "@/components/shared/SearchButton";


async function Home({
Expand All @@ -30,6 +31,8 @@ async function Home({
<>
<h1 className='head-text text-left text-black mb-4'>Recent Sparks...</h1>
<FilterBox />
<br/>
<SearchButton />
<section className='mt-9 flex flex-col gap-10'>
{result?.length === 0 ? (
<p className='no-result'>No posts found</p>
Expand Down
30 changes: 28 additions & 2 deletions app/(root)/post/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import Post from "@/components/cards/Post";

import { fetchUser } from "@/lib/actions/user.actions";
import { fetchPostById } from "@/lib/actions/post.actions";
import { updateOnlineStatus } from "@/lib/actions/chat.actions";
import Image from "next/image";
import Link from "next/link";
import { Button } from "@/components/ui/button";

export const revalidate = 0;

Expand All @@ -22,8 +24,31 @@ async function page({ params }: { params: { id: string } }) {

const post = await fetchPostById(params.id);

const kids = post.children ? post.children : []


if(!post)
{
return(
<section className="pt-16 flex flex-col justify-center items-center">
<div className="mb-8">
<Image src={"/assets/error.jpg"} alt="Error" width={300} height={300} className="rounded-xl"/>
</div>
<h1 className="text-heading3-bold mb-4">Post Not Found</h1>
<p className="text-body-bold text-gray-600 mb-8">The post you are looking for does not exist or was deleted.</p>
<Link href={"/"}>
<Button className="bg-primary-500 hover:bg-cyan-400 hover:text-black">
Home
</Button>
</Link>
</section>

)
}

if(post)
{
const kids = post.children ? post.children : []

return (
<section className='relative'>
<div>
Expand Down Expand Up @@ -79,5 +104,6 @@ const kids = post.children ? post.children : []
</section>
);
}
}

export default page;
72 changes: 72 additions & 0 deletions app/(root)/post/edit/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import React from 'react'
import { redirect } from "next/navigation";
import { currentUser } from "@clerk/nextjs";

import { fetchUser } from "@/lib/actions/user.actions";
import { fetchPostById } from "@/lib/actions/post.actions";
import Image from "next/image";
import Link from "next/link";
import EditPost from '@/components/cards/EditPost';

const page = async ({ params }: { params: { id: string } }) => {

if (!params.id) return null;

const user = await currentUser();
if (!user) return null;

const userInfo = await fetchUser(user.id);
if (!userInfo?.onboarded) redirect("/onboarding");

const post = await fetchPostById(params.id);

if(user.id !== post.author_id)
{
redirect("/")
}

if(!post)
{
return(
<section className="pt-16 flex flex-col justify-center items-center">
<div className="mb-8">
<Image src={"/assets/error.jpg"} alt="Error" width={300} height={300} className="rounded-xl"/>
</div>
<h1 className="text-heading3-bold mb-4">Post Not Found</h1>
<p className="text-body-bold text-gray-600 mb-8">The post you are looking for does not exist or was deleted.</p>
<Link href={"/"} className="bg-primary-500 text-white px-4 py-2.5 rounded-xl hover:bg-cyan-400 hover:underline hover:text-blue">
Home
</Link>
</section>

)
}

return (
<section className='relative'>
<h1 className='text-center text-heading3-bold mb-4'>Edit Post</h1>

<EditPost
key={post.idpost}
id={post.idpost}
currentUserId={user.id}
parentId={post.parent_id}
content={post.content}
createdAt={post.created_at}

image={post.author.image}
username={post.author.username}
authorId={post.author_id}
contentImage={post.image}
title={post.title}
prompt={post.prompt}
userId={user.id}
/>



</section>
)
}

export default page
68 changes: 68 additions & 0 deletions app/(root)/search-post/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Post from '@/components/cards/Post';
import Pagination from '@/components/shared/Pagination';
import Searchbar from '@/components/shared/Searchbar';
import { searchPosts } from '@/lib/actions/post.actions';
import { fetchUser } from '@/lib/actions/user.actions';
import { currentUser } from '@clerk/nextjs';
import { redirect } from 'next/navigation';
import React from 'react'

const page = async (
{
searchParams,
}: {
searchParams: { [key: string]: string | undefined };
}
) => {

const user = await currentUser();
if (!user) return null;


const userInfo = await fetchUser(user.id);
if (!userInfo?.onboarded) redirect("/onboarding");

const searchQuery = searchParams.q;
const pageNumber = searchParams?.page ? +searchParams.page : 1;
const pageSize = 6;

const result = await searchPosts({ searchQuery, pageNumber, pageSize });

return (
<>
<h1 className='head-text text-left text-black mb-4'>Search for Posts...</h1>
<Searchbar routeType='search-post' />
<section className='mt-9 flex flex-col gap-10'>
{result.results?.length === 0 ? (
<p className='no-result'>No posts found</p>
) : (
<>

{result.results.map((post: any) => (
<Post
key={post.idpost}
id={post.idpost}
currentUserId={user.id}
parentId={post.parent_Id}
content={post.content}
createdAt={post.created_at}
comments={post.children}
image={post.author_image}
contentImage={post.image}
username={post.author_username}
likes = {post.likes? post.likes: ''}
authorId = {post.author_id}
title={post.title}
prompt={post.prompt}
/>
))}

</>
)}
</section>

</>
)
}

export default page
14 changes: 8 additions & 6 deletions app/(root)/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Searchbar from "@/components/shared/Searchbar";
import Pagination from "@/components/shared/Pagination";

import { fetchUser, fetchUsers } from "@/lib/actions/user.actions";
import { updateOnlineStatus } from "@/lib/actions/chat.actions";
import SearchButton from "@/components/shared/SearchButton";

async function Page({
searchParams,
Expand All @@ -30,11 +30,13 @@ async function Page({

return (
<section>
<h1 className='head-text mb-10 text-black'>Search for Users</h1>

<h1 className='head-text mb-6 text-black'>Search for Users</h1>
<Searchbar routeType='search' />

<div className='mt-14 flex flex-col gap-9'>
<div className="py-4">
<SearchButton />
</div>

<div className='mt-8 flex flex-col gap-9'>
{result.users.length === 0 ? (
<p className='no-result'>No Result</p>
) : (
Expand All @@ -47,7 +49,7 @@ async function Page({
username={person.username}
imgUrl={person.image}
type="search"
postId={null}
postId={``}
sender = {null}
/>
))}
Expand Down
11 changes: 10 additions & 1 deletion app/api/openAIChat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ async function photographyImage(title: string, prompt: string): Promise<string |
title: Golden Serenity
synopsis: In the magical embrace of golden hour, 'Golden Serenity' unfolds as a captivating photograph that transcends time. This masterful composition, captured by a skilled photographer, invites viewers to immerse themselves in a serene landscape bathed in the warm hues of sunset. The play of light and shadow creates a canvas where nature's beauty takes center stage. At the heart of the photograph stands a tranquil scene—a reflection of a majestic tree mirrored in a still pond, surrounded by a carpet of vibrant wildflowers. The artist's lens captures the essence of the fleeting moment, freezing time to preserve the golden glow that bathes the landscape. Every detail, from the delicate ripples on the water to the whispering leaves of the tree, contributes to the narrative of serenity and tranquility. 'Golden Serenity' is a visual journey into the soul of nature, an ode to the artistry of photography that transforms fleeting moments into eternal beauty.
image description: An image of a photograph based on this: In the magical embrace of golden hour, 'Golden Serenity' captures the essence of nature's beauty. The tranquil scene unfolds with a majestic tree reflected in a still pond, surrounded by vibrant wildflowers. The warm hues of sunset create a captivating play of light and shadow, freezing the fleeting moment in time. The details, from delicate ripples to whispering leaves, tell a story of serenity and tranquility. This image is an ode to the artistry of photography, preserving the eternal beauty of nature.`
},
{
role: "user",
content: `Give a short description of an image of a photograph. The description should be rich in visual detail but contain no names.
###
title: ${title}
synopsis: ${prompt}
image description:
`
}
],
model: "gpt-3.5-turbo",
Expand Down Expand Up @@ -306,7 +315,7 @@ async function generateQuoteLiterature(prompt: string): Promise<string | null> {
{ role: "system", content: "You are a helpful assistant that generates a quote based on a sentence prompt." },
{
role: "user",
content: "Generate an engaging and good quality quote that already exisits based on a prompt. The literature work should have a Title in the beginning, keep it simple only include the quote and its author. Here is an example prompt: Oursleves and our limits"
content: "Generate an engaging and good quality quote that already exisits based on a prompt. The literature work should have a Title in the beginning, and the word synopsis: before quote, the keep it simple only include the quote and its author. Here is an example prompt: Oursleves and our limits"
},
{
role: "assistant",
Expand Down
Loading

0 comments on commit bab329e

Please sign in to comment.