Skip to content

Commit

Permalink
Implemented create propmts and saving created prompts to MongoDB data…
Browse files Browse the repository at this point in the history
…base. Implemented rendering created propmts on homepage with ability to copy prompts with a button
  • Loading branch information
GIT-Gizmo committed Oct 9, 2023
1 parent ba2229a commit 16c624c
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 8 deletions.
21 changes: 21 additions & 0 deletions app/api/prompt/new/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { connectToDB } from "@utils/database";
import Prompt from '@models/prompt';

export const POST = async (req) => {
const { userId, prompt, tag } = await req.json();

try {
await connectToDB();
const newPrompt = new Prompt({
creator: userId,
prompt,
tag
})

await newPrompt.save();

return new Response(JSON.stringify(newPrompt), { status: 201 })
} catch (error) {
return new Response("Failed to create a new prompt", { status: 500 })
}
}
14 changes: 14 additions & 0 deletions app/api/prompt/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { connectToDB } from "@utils/database";
import Prompt from '@models/prompt';

export const GET = async (request) => {
try {
await connectToDB();

const prompts = await Prompt.find({}).populate('creator');

return new Response(JSON.stringify(prompts), { status: 200 })
} catch (error) {
return new Response("Failed to fetch all prompts", { status: 500 })
}
}
55 changes: 55 additions & 0 deletions app/create-prompt/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use client';

import { useState } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/navigation';

import Form from '@components/form';
import { set } from 'mongoose';

const CreatePrompt = () => {
const router = useRouter();
const { data: session } = useSession();

const [submitting, setSubmitting] = useState(false);
const [post, setPost] = useState({
prompt: '',
tag: '',
})

const createPrompt = async (e) => {
e.preventDefault();
setSubmitting(true);

try {
const response = await fetch('/api/prompt/new', {
method: 'POST',
body: JSON.stringify({
prompt: post.prompt,
userId: session?.user.id,
tag: post.tag
})
})

if(response.ok) {
router.push('/');
}
} catch (error) {
console.log(error);
} finally {
setSubmitting(false);
}
}

return (
<Form
type="Create"
post={post}
setPost={setPost}
submitting={submitting}
handleSubmit={createPrompt}
/>
)
}

export default CreatePrompt
53 changes: 51 additions & 2 deletions components/Feed.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,57 @@
import React from 'react'
'use client';

import { useState, useEffect } from 'react';

import PromptCard from './PromptCard';

const PromptCardList = ({ data, handleTagClick}) => {
return (
<div className="mt-16 prompt_layout">
{data.map((post) => (
<PromptCard
key={post._id}
post={post}
handleTagClick={handleTagClick}
/>
))}
</div>
)
}

const Feed = () => {
const [searchText, setSearchText] = useState('');
const [posts, setPosts] = useState([]);

const handleSearchChange = (e) => {

}

useEffect(() => {
const fetchPosts = async () => {
const response = await fetch('api/prompt');
const data = await response.json();

setPosts(data);
}

fetchPosts();
}, []);

return (
<div>Feed</div>
<section className='feed'>
<form className='relative w-full flex-center'>
<input type="text"
placeholder='Search for tags or username'
value={searchText}
onChange={handleSearchChange}
required
className='search_input peer' />
</form>

<PromptCardList
data={posts}
handleTagClick={() => {}} />
</section>
)
}

Expand Down
45 changes: 42 additions & 3 deletions components/Form.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,47 @@
import React from 'react'
import Link from 'next/link';

const Form = () => {
const Form = ({ type, post, setPost, submitting, handleSubmit, }) => {
return (
<div>Form</div>
<section className='w-full max-w-full flex-start flex-col'>
<h1 className="head_text text-left">
<span className="blue_gradient">{type} Post</span>
</h1>

<p className="desc text-left max-w-md">{type} and share amazing prompts with the world, and let your imagination run wild with any AI-powered platform.</p>

<form onSubmit={handleSubmit} className='mt-10 w-full max-w-2xl flex flex-col gap-7 glassmorphism'>
<label>
<span className="font-satoshi font-semibold text-base text-gray-700">
Your AI Prompt
</span>

<textarea value={post.prompt} onChange={(e) => setPost({ ...post,
prompt: e.target.value })} placeholder='Write your prompt here...' required
className='form_textarea' />
</label>

<label>
<span className="font-satoshi font-semibold text-base text-gray-700">
Tags {` `}
<span className='font-normal'>(#resume, #webdevelopment, #jobs)</span>
</span>

<input value={post.tag} onChange={(e) => setPost({ ...post,
tag: e.target.value })} placeholder='#tag' required
className='form_input' />
</label>

<div className='flex-end mx-3 mb-5 gap-4'>
<Link href="/" className='text-gray-500 text-sm'>
Cancel
</Link>

<button type='submit' disabled={submitting} className='px-5 py-1.5 text-sm bg-primary-orange rounded-full text-white'>
{submitting ? `${type}...` : type}
</button>
</div>
</form>
</section>
)
}

Expand Down
50 changes: 47 additions & 3 deletions components/PromptCard.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
import React from 'react'
"use client";

import { useState } from 'react';
import Image from 'next/image';
import { usePathname, useRouter } from 'next/navigation';
import { useSession } from 'next-auth/react';

const PromptCard = ({ post, handleTagClick, handleEdit, handleDelete }) => {
const [copied, setCopied] = useState("");

const handleCopy = () => {
setCopied(post.prompt);
navigator.clipboard.writeText(post.prompt);
setTimeout(() => setCopied(""), 3000);
}

const PromptCard = () => {
return (
<div>PromptCard</div>
<div className='prompt_card'>
<div className="flex justify-between items-start gap-5">
<div className='flex-1 flex justify-start items-center gap-3 cursor-pointer'>
<Image
src={post.creator.image}
alt='User image'
width={40}
height={40}
className='rounded-full object-contain' />

<div className="flex flex-col">
<h3 className='font-satoshi font-semibold text-gray-900'>
{post.creator.username}
</h3>
<p className='font-inter text-sm text-gray-500'>
{post.creator.email}
</p>
</div>
</div>

<div className="copy_btn" onClick={handleCopy}>
<Image
src={copied === post.prompt ? '/assets/icons/tick.svg' : '/assets/icons/copy.svg'}
width={12}
height={12} />
</div>
</div>

<p className='my-4 font-satoshi text-sm text-gray-700'>{post.prompt}</p>
<p className='font-inter text-sm blue_gradient cursor-pointer'
onClick={() => handleTagClick && handleTagClick(post.tag)}>{post.tag}</p>
</div>
)
}

Expand Down
20 changes: 20 additions & 0 deletions models/prompt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Schema, model, models } from 'mongoose';

const PromptSchema = new Schema({
creator: {
type: Schema.Types.ObjectId,
ref: 'User',
},
prompt: {
type: String,
required: [true, 'Prompt is required.'],
},
tag: {
type: String,
required: [true, 'Tag is required.'],
}
});

const Prompt = models.Prompt || model('Prompt', PromptSchema);

export default Prompt;

0 comments on commit 16c624c

Please sign in to comment.