Skip to content

Commit

Permalink
feat: add posts components
Browse files Browse the repository at this point in the history
  • Loading branch information
subhamX committed Aug 17, 2022
1 parent 5eb792c commit 2d4cc97
Show file tree
Hide file tree
Showing 29 changed files with 664 additions and 130 deletions.
100 changes: 0 additions & 100 deletions components/Navbar.tsx/index.tsx

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
38 changes: 38 additions & 0 deletions frontend/components/Forms/FormInputField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@


import { ErrorMessage, Field } from "formik";
import { InputHTMLAttributes } from "react";

export const FormInputField = ({
fieldId,
fieldLabel,
placeholder,
isInline,
type = "text",
...props
}: {
fieldId: string;
placeholder?: string;
isInline?: boolean;
fieldLabel?: string;
type?: string;

} & InputHTMLAttributes<any>) => (
<label
className={`input-group h-full w-full text-sm ${
isInline ? "flex-row" : "flex-col"
}`}
>
{fieldLabel && <div className="label w-full pb-1">{fieldLabel}</div>}
<Field
name={fieldId}
type={type}
id={fieldId}
autoComplete="off"
{...props}
placeholder={placeholder}
className="input input-bordered px-3 min-h-full border-black bg-slate-50 w-full"
/>
<ErrorMessage className="text-red-500 text-xs mt-1" name={fieldId} />
</label>
);
File renamed without changes.
File renamed without changes.
107 changes: 107 additions & 0 deletions frontend/components/Navbar.tsx/MainSiteNavbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Menu } from "@headlessui/react"
import Link from "next/link"
import { ReactNode } from "react"
import { BLOG_URL, DASHBOARD_URL, FEATURES_URL_HASH, NEW_USER_WELCOME_URL } from "../../config/ScreenRoutes"


export const MainSiteNavbar = ({ leadingBlock }: { leadingBlock?: ReactNode }) => {
const is_logged_in = true;

return (
<div className="min-h-16 px-4 flex border-b-black border-b">
<nav className="mx-auto w-full max-w-6xl flex items-center justify-between gap-7">
{leadingBlock ? leadingBlock : <div className="font-bold text-2xl text-left flex-grow">WingMate</div>}
<div className="hidden sm:flex justify-between flex-grow items-center">
<div className="flex justify-between gap-5">
<Link href={FEATURES_URL_HASH}>
<div className="cursor-pointer hover:underline decoration-dashed">Features</div>
</Link>
<Link href={BLOG_URL}>
<div className="cursor-pointer hover:underline decoration-dashed">Blog</div>
</Link>

</div>
<div className="flex gap-3 items-center">

{is_logged_in ?
<Link href={DASHBOARD_URL}>
{/* Only for Authenticated User */}
<div className="btn btn-sm btn-primary">Dashboard</div>
</Link>
:
<Link href={NEW_USER_WELCOME_URL}>
{/* Only for Non Authenticated User */}
<div className="btn btn-sm btn-primary">Login</div>
</Link>}
</div>
</div>

<Menu>
{({ open }) => (
<>
<Menu.Button className='block text-sm xss:text-base sm:hidden'>{open ? 'Close' : 'Menu'}</Menu.Button>
<MyDropdown is_logged_in={is_logged_in} />
</>
)}

</Menu>

</nav>
</div>

)
}


function MyDropdown({ is_logged_in }: { is_logged_in: boolean }) {
return (
<>
<Menu.Items className='sm:hidden bg-base-100 absolute top-16 left-0 bottom-0 right-0 z-50'>
<Menu.Item as='div' className='cursor-pointer w-full px-5 py-4 border-b border-b-black'>
<Link
href={FEATURES_URL_HASH}
>
<div className="">
Features
</div>
</Link>
</Menu.Item>
<Menu.Item as='div' className='cursor-pointer w-full px-5 py-4 border-b border-b-black'>
<Link
href={BLOG_URL}
>
<div className="">
Blog
</div>
</Link>
</Menu.Item>

{is_logged_in ?
<Menu.Item as='div' className='cursor-pointer w-full px-5 py-4 border-b border-b-black'>
{/* Only for Authenticated User */}

<Link
href={DASHBOARD_URL}
>
<div className="">
Dashboard
</div>
</Link>
</Menu.Item>
:
<Menu.Item as='div' className='cursor-pointer w-full px-5 py-4 border-b border-b-black'>
{/* Only for Non Authenticated User */}
<Link
href={NEW_USER_WELCOME_URL}
>
<div className="">
Login
</div>
</Link>
</Menu.Item>
}
</Menu.Items>
</>

)
}
14 changes: 14 additions & 0 deletions frontend/components/Navbar.tsx/UserProfileSiteLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const UserProfileSiteLogo = ({siteTitle}: {siteTitle: string}) => (
<div className="">
<div className="flex items-center gap-2">
<div className="hidden xss:block avatar">
<div className="h-8 rounded-full">
<img src="https://unsplash.com/photos/wQLAGv4_OYs/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8MjB8fHVzZXIlMjBwcm9maWxlJTIwYWJzdHJhY3R8ZW58MHx8fHwxNjYwNTkxNzY2&force=true&w=100" />
</div>
</div>
<div className="flex flex-col">
<div className="font-medium text-lg">{siteTitle}</div>
</div>
</div>
</div>
);
135 changes: 135 additions & 0 deletions frontend/components/PostsDetailed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { BookOpenIcon, ChatAltIcon, HeartIcon } from "@heroicons/react/solid";
import { Form, Formik } from "formik";
import { FormInputField } from "./Forms/FormInputField";
import { MainSiteNavbar } from "./Navbar.tsx/MainSiteNavbar";
import { UserProfileSiteLogo } from "./Navbar.tsx/UserProfileSiteLogo";


type CommentProp = {
user_avatar: string,
name: string,
posted_at: string,
comment: string,
is_deleted: boolean,
}

type Props = {
post: {
title: string,
body: string, // full markdown
published_on: string, // date

post_id: string;
owner_id: string;

liked_by: number,
number_of_comments: number;
cover_image_url: string,
approx_read_time_in_minutes: number,
},
isPostLoading: boolean
loadMoreCommentsHandler: () => void,
postCommentHandler: (comment: string) => void
comments: CommentProp[]
}

export const PostsDetailedScreen = ({ post, isPostLoading, loadMoreCommentsHandler, comments, postCommentHandler }: Props) => {
return (<>

<MainSiteNavbar leadingBlock={
<UserProfileSiteLogo siteTitle={'heya'} />
} />
{isPostLoading ?
<div className="alert max-w-3xl my-2 mx-auto alert-info">Fetching post... ⟨䷄⟩</div>
:
<div className="max-w-4xl mx-auto">
<img src={post.cover_image_url} className='flex-grow h-64 w-full' />
<div className="px-4">
<div className="text-4xl font-black my-5">{post.title}</div>

<div className="flex items-center gap-2 text-sm text-gray-400 pt-1">
{new Date(post.published_on).toDateString()}


<BookOpenIcon className='w-6' />
{post.approx_read_time_in_minutes} min read

</div>

<div className="text-sm text-gray-500 pt-3 pb-4">
TODO: Render markdown
{post.body}
</div>


<div className="flex gap-5 text-xs mb-7">
<div className='flex text-pink-400 flex-col justify-center items-center'>
<HeartIcon className='w-6' />
{post.liked_by}
</div>
<div className="flex flex-col text-blue-400 justify-center items-center">
<ChatAltIcon className='w-6' />
{post.number_of_comments}
</div>
</div>
<CommentsUI hasMore postCommentHandler={postCommentHandler} comments={comments} loadMoreCommentsHandler={loadMoreCommentsHandler} />

</div>

</div>
}


</>
)
}


const CommentsUI = ({ comments, hasMore, postCommentHandler, loadMoreCommentsHandler }: { comments: CommentProp[], hasMore: boolean, loadMoreCommentsHandler: () => void, postCommentHandler: (comment: string) => void }) => {
// fetch user


const userAvatar = "https://unsplash.com/photos/wQLAGv4_OYs/download?ixid=MnwxMjA3fDB8MXxzZWFyY2h8MjB8fHVzZXIlMjBwcm9maWxlJTIwYWJzdHJhY3R8ZW58MHx8fHwxNjYwNTkxNzY2&force=true&w=100"
const isLoggedIn = true

return (
<div className="bg-base-200">
<div className="p-5">
{hasMore && <div className="text-gray-400 font-bold text-xs cursor-pointer" onClick={loadMoreCommentsHandler}>Load previous comments...</div>}

{comments.map((e, indx) => (
<div className="text-sm mt-2 mb-5" key={indx}>
<div className="flex items-center gap-5">
<div className="avatar">
<div className="w-10 rounded-full">
<img src={e.user_avatar} />
</div>
</div>
<div className="bg-base-100 rounded py-2 px-3">
<div className="font-medium space-x-2"><span>{e.name}</span> <span className="text-gray-500 text-xs">{new Date(e.posted_at).toDateString()}</span></div>
<div className="text-gray-500">{e.comment}</div>
</div>
</div>
</div>
))}


<Formik onSubmit={(e) => postCommentHandler(e.new_comment)} initialValues={{ new_comment: '' }}>
<Form>
<div className="flex gap-5 h-10 items-center">
<div className="avatar">
<div className="w-10 rounded-full">
<img src={userAvatar} />
</div>
</div>
<FormInputField required fieldId="new_comment" placeholder="Add comment..." />
<button className="btn btn-primary btn-sm h-full" >Submit</button>
</div>
</Form>

</Formik>
</div>
</div>
)

}
Loading

0 comments on commit 2d4cc97

Please sign in to comment.