Skip to content

Commit

Permalink
feat: enhance random user display and add new textarea component
Browse files Browse the repository at this point in the history
  • Loading branch information
ng-jayson committed Nov 22, 2024
1 parent 4af434b commit 41ef497
Show file tree
Hide file tree
Showing 11 changed files with 1,034 additions and 898 deletions.
20 changes: 0 additions & 20 deletions app/explore/_components/post/post-container.tsx

This file was deleted.

335 changes: 152 additions & 183 deletions app/explore/_components/post/post-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@ import { SafeUser } from "@/types";
import useAutosizeTextArea from "@/lib/state/useAutosizeTextArea";

import { Button } from "@/components/shared/button";
import { GradiantCard } from "@/components/shared/gradiant-card";
import { Plus } from "lucide-react";
import { Paperclip } from "lucide-react";
import { Label } from "@/components/shared/label";
import DialogFit from "@/components/shared/dialog-fit";
import LoadingDots from "@/components/shared/icons/loading-dots";

const PostForm = ({ currUser }: { currUser?: SafeUser }) => {
import {
Dialog,
DialogTrigger,
DialogContent,
DialogTitle,
DialogDescription,
} from "@/components/shared/dialog";
import { Input } from "@/components/shared/input";

const PostForm = ({ currUser }: { currUser: SafeUser }) => {
const [title, setTitle] = useState<string>("");
const [message, setMessage] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false);
Expand All @@ -24,8 +31,6 @@ const PostForm = ({ currUser }: { currUser?: SafeUser }) => {
useState<boolean>(false);
const [titleCharacterCount, setTitleCharacterCount] = useState<number>(0);
const [messageCharacterCount, setMessageCharacterCount] = useState<number>(0);
useState<boolean>(false);

const [tags, setTags] = useState("");

const textAreaRef = useRef<HTMLTextAreaElement>(null);
Expand Down Expand Up @@ -98,187 +103,151 @@ const PostForm = ({ currUser }: { currUser?: SafeUser }) => {
};

return (
<>
<GradiantCard variant="clean">
<h1 className="font-heading text-xl font-bold tracking-wide">
Start a new discussion!
</h1>
<form
className="mt-3 flex w-full flex-col gap-3"
onSubmit={async (e) => {
e.preventDefault();
let array: string[] = [];
if (tags !== "") {
const wordsInsideQuotes = tags.replace(/'/g, "");
const elements = wordsInsideQuotes.split(",");

array = elements.map((element) => element.trim().toLowerCase());
}

setLoading(true);
const fields = {
title: title,
message: message,
image: imageUrl,
tags: array.slice(0, 3),
};

const set = await fetch(`/api/explore/post?id=${currUser?.id}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(fields),
cache: "no-store",
});
const msg = await set.json();
if (!set.ok) {
setLoading(false);
toast.error(msg.message);
} else {
setLoading(false);
toast.success("Successfully posted! Please wait.");

window.location.reload();
}
}}
>
<div className="flex h-fit items-center gap-2.5 rounded-lg p-2 pt-0">
<Image
src={(currUser?.image as string) || "/nana.jpg"}
alt="image"
width={48}
height={48}
className="h-12 w-12 rounded-full object-cover"
/>
<textarea
placeholder="Title"
className="w-full resize-none overflow-hidden rounded-lg border-b border-slate-700 bg-transparent px-3 py-2 text-slate-200 outline-none transition-all duration-500 focus:outline-none"
onChange={(e) => {
const inputValue = e.target.value;
setTitle(inputValue);
setTitleCharacterCount(inputValue.length);
}}
maxLength={50}
value={title}
rows={1}
/>
</div>

<div className="space-y-1">
<textarea
className="w-full resize-none overflow-hidden rounded-lg border border-slate-700 bg-transparent p-3 text-slate-200 outline-none transition-all duration-100 focus:outline-none focus:ring"
onChange={(e) => {
const inputValue = e.target.value;
setMessage(inputValue);
setMessageCharacterCount(inputValue.length);
}}
onFocus={() => setIsMessageInputFocused(true)}
onBlur={() => setIsMessageInputFocused(false)}
maxLength={2000}
placeholder="Message"
ref={textAreaRef}
value={message}
rows={5}
/>
{isMessageInputFocused && (
<p className="text-[10px] text-neutral-500">
{messageCharacterCount} / {2000} characters
</p>
)}
</div>
<div className="space-y-1">
<Label htmlFor="tags">Tags (Optional)</Label>
<input
type="text"
placeholder={"Enter up to 3 tags (e.g. heroes, meta, bug)"}
value={tags}
id="tags"
onChange={(e) => {
const inputValue = e.target.value;
setTags(inputValue);
}}
className="w-full resize-none overflow-hidden rounded-lg border border-slate-700 bg-transparent p-3 text-sm text-slate-200 outline-none transition-all duration-100 focus:outline-none focus:ring"
/>
</div>
<Dialog>
<DialogTrigger asChild>
<Button variant="gradiantNavy">
<Plus className="h-4 w-4 sm:mr-2" />
<span className="hidden sm:block">Start Discussion</span>
</Button>
</DialogTrigger>
<DialogContent>
<DialogTitle>Start a new discussion!</DialogTitle>
<DialogDescription>
<form
className="mt-3 flex w-full flex-col gap-3"
onSubmit={async (e) => {
e.preventDefault();
let array: string[] = [];
if (tags !== "") {
const wordsInsideQuotes = tags.replace(/'/g, "");
const elements = wordsInsideQuotes.split(",");

array = elements.map((element) => element.trim().toLowerCase());
}

<div className="flex items-center justify-end gap-2">
<DialogFit
title="Choose image (Max 5 MB)"
triggerChild={
<Paperclip className="mr-2 mt-1 cursor-pointer transition-all ease-in-out hover:text-ocean hover:duration-300" />
setLoading(true);
const fields = {
title: title,
message: message,
image: imageUrl,
tags: array.slice(0, 3),
};

const set = await fetch(`/api/explore/post?id=${currUser?.id}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(fields),
cache: "no-store",
});
const msg = await set.json();
if (!set.ok) {
setLoading(false);
toast.error(msg.message);
} else {
setLoading(false);
toast.success("Successfully posted! Please wait.");

window.location.reload();
}
}}
>
<div className="flex h-fit items-center gap-2.5 rounded-lg p-2 pt-0">
<Image
src={(currUser?.image as string) || "/nana.jpg"}
alt="image"
width={48}
height={48}
className="h-12 w-12 rounded-full object-cover"
/>
<textarea
placeholder="Title"
className="w-full resize-none overflow-hidden rounded-lg border-b border-slate-700 bg-transparent px-3 py-2 text-slate-200 outline-none transition-all duration-500 focus:outline-none"
onChange={(e) => {
const inputValue = e.target.value;
setTitle(inputValue);
setTitleCharacterCount(inputValue.length);
}}
maxLength={50}
value={title}
rows={1}
/>
</div>

<div className="space-y-1">
<textarea
className="w-full resize-none overflow-hidden rounded-lg border border-slate-700 bg-transparent p-3 text-slate-200 outline-none transition-all duration-100 focus:outline-none focus:ring"
onChange={(e) => {
const inputValue = e.target.value;
setMessage(inputValue);
setMessageCharacterCount(inputValue.length);
}}
onFocus={() => setIsMessageInputFocused(true)}
onBlur={() => setIsMessageInputFocused(false)}
maxLength={2000}
placeholder="Message"
ref={textAreaRef}
value={message}
rows={5}
/>
{isMessageInputFocused && (
<p className="text-[10px] text-neutral-500">
{messageCharacterCount} / {2000} characters
</p>
)}
</div>
<div className="space-y-1">
<Label htmlFor="tags">Optional</Label>
<Input
type="text"
placeholder={"Enter up to 3 tags (e.g. heroes, meta, bug)"}
value={tags}
id="tags"
onChange={(e) => {
const inputValue = e.target.value;
setTags(inputValue);
}}
className="w-full resize-none overflow-hidden rounded-lg border border-slate-700 bg-transparent p-3 text-sm text-slate-200 outline-none transition-all duration-100 focus:outline-none focus:ring"
/>
</div>

<div
className="cursor-pointer rounded-lg border border-slate-700 p-3 text-sm text-slate-200 transition-all duration-100 hover:bg-slate-800"
{...getRootProps()}
>
<div>
<div className="flex flex-col items-center justify-center">
{selectedImage && (
<Image
src={`${URL.createObjectURL(selectedImage)}`}
alt=""
width={0}
height={0}
sizes="100vw"
className="h-auto w-auto"
/>
)}
</div>
<div className="cursor-pointer text-sm" {...getRootProps()}>
<input {...getInputProps()} />
{isDragActive ? (
<div className="my-4 flex cursor-pointer flex-row items-center justify-center">
<Paperclip className="mr-1 mt-[1px] h-3 w-3" />
<p className="font-semiboldtext-decoration: text-sm underline underline-offset-2">
Drop file here
</p>
</div>
) : (
<div className="my-4 flex cursor-pointer flex-row items-center justify-center">
<Paperclip className="mr-1 mt-[1px] h-3 w-3" />
<p className="text-decoration: text-sm font-semibold underline underline-offset-2">
Drag and drop file here, or click to select and replace
file
</p>
</div>
)}
</div>

<Button
disabled={!selectedImage}
onClick={(e) => {
handleUpload(e);
setLoading(true);
setButtonDisabled(true);
}}
variant="gradiantNavy"
className="mt-4 w-full"
>
{loading ? (
<>
<LoadingDots color="#FAFAFA" />
</>
) : (
"Done"
)}
</Button>
<input {...getInputProps()} />
<div className="flex flex-row items-center justify-center">
<Paperclip className="mr-2 h-4 w-4" />
{isDragActive ? (
<p className="font-semibold">Drop image here</p>
) : (
<p className="font-semibold">
Upload/replace by clicking or dropping an image
</p>
)}
</div>
</DialogFit>
<Button
className="mt-1 w-full rounded-2xl"
variant="gradiantNavy"
disabled={!title || !message}
>
{loading ? (
<>
<LoadingDots color="#FAFAFA" />
</>
) : (
"Post"
)}
</Button>
</div>
</form>
</GradiantCard>
</>
</div>

<div className="flex items-center justify-end gap-2">
<Button
className="mt-1 w-full rounded-2xl text-cloud"
variant="gradiantNavy"
disabled={!title || !message}
>
{loading ? (
<>
<LoadingDots color="#FAFAFA" />
</>
) : (
"Post"
)}
</Button>
</div>
</form>
</DialogDescription>
</DialogContent>
</Dialog>
);
};

Expand Down
Loading

1 comment on commit 41ef497

@github-actions
Copy link

Choose a reason for hiding this comment

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

Deploy preview for mlbb-fyi ready!

✅ Preview
https://mlbb-peeg762jg-jinjays.vercel.app

Built with commit 41ef497.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.