Skip to content

Commit

Permalink
Merge pull request #268 from Shelf-nu/138-implementing-optimistic-ui
Browse files Browse the repository at this point in the history
138 implementing optimistic UI
  • Loading branch information
DonKoko authored Aug 1, 2023
2 parents 26cb749 + f25e76d commit d482a39
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 15 deletions.
2 changes: 1 addition & 1 deletion app/components/assets/notes/actions-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface Props {
}

export const ActionsDopdown = ({ note }: Props) => (
<DropdownMenu>
<DropdownMenu modal={false}>
<DropdownMenuTrigger>
<HorizontalDotsIcon />
</DropdownMenuTrigger>
Expand Down
18 changes: 9 additions & 9 deletions app/components/assets/notes/new.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import type { ChangeEvent, FocusEvent } from "react";
import { useCallback, useEffect, useRef } from "react";
import { useFetcher, useParams } from "@remix-run/react";
import type { FetcherWithComponents } from "@remix-run/react";
import { useParams } from "@remix-run/react";
import { atom, useAtom } from "jotai";
import { useZorm } from "react-zorm";
import { z } from "zod";
import Input from "~/components/forms/input";
import { MarkdownEditor, clearMarkdownAtom } from "~/components/markdown";
import { Button } from "~/components/shared";
import { Spinner } from "~/components/shared/spinner";
import { isFormProcessing } from "~/utils";

export const NewNoteSchema = z.object({
content: z.string().min(3, "Content is required"),
});

const isEditingAtom = atom(false);

export const NewNote = () => {
export const NewNote = ({
fetcher,
}: {
fetcher: FetcherWithComponents<any>;
}) => {
const zo = useZorm("NewQuestionWizardScreen", NewNoteSchema);
const fetcher = useFetcher();
const params = useParams();
const disabled = isFormProcessing(fetcher.state);
const hasError = zo.errors.content()?.message;
const [isEditing, setIsEditing] = useAtom(isEditingAtom);
const editorRef = useRef<HTMLTextAreaElement>(null);
Expand Down Expand Up @@ -89,13 +90,12 @@ export const NewNote = () => {
>
Cancel
</Button>
<Button type="submit" size="sm" className="" disabled={disabled}>
{disabled ? <Spinner /> : "Create note"}
<Button type="submit" size="sm" className="">
Create note
</Button>
</div>
<MarkdownEditor
label={"note"}
disabled={disabled}
defaultValue={""}
name={zo.fields.content()}
placeholder={"Leave a note"}
Expand Down
2 changes: 1 addition & 1 deletion app/components/assets/notes/note.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const Update = ({
</div>
);

const Comment = ({
export const Comment = ({
note,
user,
}: {
Expand Down
35 changes: 31 additions & 4 deletions app/components/assets/notes/notes.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
import { useLoaderData } from "@remix-run/react";

import { useLoaderData, useFetcher } from "@remix-run/react";
import { MarkdownViewer } from "~/components/markdown/markdown-viewer";
import { useUserData } from "~/hooks";
import { isFormProcessing } from "~/utils";
import { NewNote } from "./new";
import type { NoteWithDate } from "./note";
import { Note } from "./note";

export const Notes = () => {
const { asset } = useLoaderData();
/* Using user data here for the Note component generated for frontend only as per the optimistic UI approach */
const user = useUserData();
const hasNotes = asset?.notes.length > 0;

/* Importing fetcher here in the parent file such that we can use fetcher's states to know the status of form processing and form data render the frontend component on the fly (Optimistic UI) and in the new note form this fetcher is passed as a prop */
const fetcher = useFetcher();
let onSubmissionContent = "";
/* Getting the form data using fetcher and storing the content of form in onSubmissionContent Variable */
if (fetcher.formData) {
for (const data of fetcher.formData.entries()) {
onSubmissionContent = data[1].toString();
}
}
return (
<div>
<NewNote />
<NewNote fetcher={fetcher} />
{hasNotes ? (
<ul className="notes-list mt-8 w-full">
{isFormProcessing(fetcher.state) ? (
<li className="note mb-6 rounded-lg border bg-white md:mb-8">
<header className="flex justify-between border-b px-3.5 py-3 text-text-xs md:text-text-sm">
<div>
<span className="commentator font-medium text-gray-900">
{user?.firstName} {user?.lastName}
</span>{" "}
<span className="text-gray-600">Just Now</span>
</div>
</header>
<div className="message px-3.5 py-3">
<MarkdownViewer content={onSubmissionContent} />
</div>
</li>
) : null}
{asset.notes.map((note: NoteWithDate) => (
<Note key={note.id} note={note} />
))}
Expand Down

0 comments on commit d482a39

Please sign in to comment.