Major League Baguette logo
Published on

IndiesReadIt Development Diary - Week 3

Authors
Table of Contents

IndiesReadIt Development Diary - Week 3

In the third week of IndiesReadIt's evolution, I delved into refining admin features and enhancing user interactions. Here's a detailed look at the week's journey:

Development Summary

18/12 - 2h+ - UI Enhancements and Domain Claim

  • Bought IndiesRead.it because I’m already posting about it on X, would be a shame if some troll steals my domain… .it is under Italian juridiction tho, let’s see how it goes..
  • Finished slug routing for category
  • Made the combobox to redirect to cat page, for SEO purpose I chose to redirect to a whole new page so I’ll get a lot of page to step up the SEO game (multiple search queries)
  • Launched majorleaguebaguette.com blog!

19/12 - 3h+ - Logic and Functionality

  • Wired the book types toggles (physical, audio & ebook) AND search
  • Copilot made spared me atleast 1h of coding, just chat your idea using @workspace so it knows your entire codebase and ask him what you want, it generates almost perfect code or atleast guide you on the right track
  • I used to block on bugs or lack ok knowledge for days, it’s not the case anymore
  • Finally used Context instead of props drilling, it was about time, here an example :
import React, { createContext, useState, useContext } from "react";
import { ExtendedBooks } from "types";

const BooksContext = createContext<
  | {
      books: ExtendedBooks[];
      setBooks: React.Dispatch<React.SetStateAction<ExtendedBooks[]>>;
    }
  | undefined
>(undefined);

export const BooksProvider: React.FC<{
  initialBooks: ExtendedBooks[];
  children: React.ReactNode;
}> = ({ initialBooks, children }) => {
  const [books, setBooks] = useState(initialBooks);

  return (
    <BooksContext.Provider value={{ books, setBooks }}>
      {children}
    </BooksContext.Provider>
  );
};

export const useBooks = () => {
  const context = useContext(BooksContext);
  if (context === undefined) {
    throw new Error("useBooks must be used within a BooksProvider");
  }
  return context;
};
<BooksProvider initialBooks={books}>
  <div className="z-10">
    <div className="border-b p-8">
      <h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
        Collaborative directory of hand-picked books for indies.
      </h1>
      <h2 className="scroll-m-20 pb-4 text-3xl font-semibold italic tracking-tight transition-colors">
        Best books by rating
      </h2>
      <Button>
        <PlusIcon className="mr-2 h-4 w-4" />
        Submit a book
      </Button>
    </div>
    <FilterBar />
    <MainLayout />
  </div>
</BooksProvider>
export const MainLayout = () => {
  const { books } = useBooks();
  return (
    <div className="grid grid-cols-1 gap-8 p-8 md:grid-cols-2 lg:grid-cols-3">
      {books ? (
        books.map((book) => <BookCard key={book.title} book={book} />)
      ) : (
        <div>no books</div>
      )}
    </div>
  );
};
  • After a book author I commented book on X asked if submit book function was active, I decided to focus on this one
  • Wanted to do a ultra basic form that email me the result but found out it wasn’t as easy as a thought so I went for the complete implementation
  • Took me less than 1 hour thanks to shadcn/ui react-hook-form and zod!
  • Getting user session to redirect to login page if unauth was more tricky and got me blocked for 2 hours until I re-discovered the useSession hook…
  • Main problem was the client and server component differenciation, I’m not used to it for now

20/12 - 3h+ - Session Handling and Refinements

  • Wasted 1 hour on trying to get the session info in client component, all I had to do was to provide the session context from layout.tsx to providers.ts and then use “const session = useSession()” where I want.
const session = await getServerSession(authOptions);
return (
  <html lang="en">
    <body className={cx(sfPro.variable, inter.variable)}>
      <div className="fixed h-screen w-full bg-gradient-to-br from-indigo-50 via-white to-cyan-100" />
      <Suspense fallback="...">
        <Nav />
      </Suspense>
      <main className="flex min-h-screen w-full flex-col items-center justify-start py-32">
        <Providers session={session}>{children}</Providers>
      </main>
      <Footer />
      <Analytics />
      <Toaster />
    </body>
  </html>
);
export default function Providers({
  children,
  session,
}: {
  children: React.ReactNode;
  session: any;
}) {
  const [queryClient] = useState(() => new QueryClient());

  return (
    <QueryClientProvider client={queryClient}>
      <SessionProvider session={session}>{children}</SessionProvider>
    </QueryClientProvider>
  );
}
  • I added auto modal close on submit success + toast in less than 5min thanks to shadcn again.
  • I switched from VercelDB to supabase in 10min too, Vercel storage and DB options are overpriced and very limited, avoid them.
  • Added final url IndiesRead.it to google credential to make Next-Auth to work.

21/12 - 4h+ - Diverse Development

  • Updated Book Prisma schema to accept 3 types of link (physical/audio/ebook), I hope it’ll encourage more people to buy from here.
  • I added my first book from an actual user : The Chameleon Founder by @matteomosca
  • I asked him how it went, had already some feedback from X (no explicit return from submission, already updated), he confirmed me that asking category from the form was a good idea
  • I’ll now try to reach more indie authors to get some coverage and early users
  • Created a new logo from freshly shipped logofas.st by @marc_louvion on X, easy way to get a better logo and he often retweet or gives credit, which is very fair and nice from him
  • Tried for 1 hour to get the opengraph-image generation from Nextjs 13+ to work but no success.
  • I went for the old way and created the OG and Twitter (630 vs 675 pixel height…) on Canva.
IndiesReadIt OG Image
  • Added a connect dot pattern to background from https://fffuel.co/ and updated bg colors as I had a little work time tonight (I often do little aesthetic updates if I know I only have few minutes, it’s a bad idea to start a feature and rush it)
  • Here the code to implement it :
<html lang="en">
      <body lang="en" className={GeistSans.className}>
        <div className="fixed h-screen w-full bg-gradient-to-br from-rose-200 via-white to-rose-50" />
        <div
          className="fixed h-screen w-full opacity-30"
          style={{
            backgroundAttachment: "fixed",
            backgroundImage: "url(/ooorganize.svg)",
            backgroundBlendMode: "overlay",
          }}
        />

...
IndiesReadIt OG Image

22/12 - 1h - Stylistic Updates

  • Improved text description at back of cards, line-clamp-[…] must be encapsulated in it’s own div
  • Improved category combobox by making it return to all books when unselect category. Made search bar to take author in count.
const action = (currentValue: string | string[]) => {
  if (currentValue === value)
    return setValue(''), setOpen(false), router.push(`/`);
  if (currentValue !== value)
    return (
      setValue(currentValue),
      setOpen(false),
      router.push(`/categories/${currentValue}`)
    );
};

Week 3 Summary

For Weeks 3, key highlights include significant UI enhancements, the acquisition of the domain IndiesRead.it to fortify the project's online presence, and the launch of the majorleaguebaguette.com blog. I tackled challenges such as session handling, refined user interactions, and implemented admin empowerment features like an "Add a Book" form.


Submit your favorite indie books to IndiesReadIt and help build this collaborative directory.

Stay tuned for more updates!