<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: BrainRepo</title>
    <description>The latest articles on Forem by BrainRepo (@brainrepo).</description>
    <link>https://forem.com/brainrepo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F401690%2Febbf948e-0017-404b-9e85-c72145228129.jpeg</url>
      <title>Forem: BrainRepo</title>
      <link>https://forem.com/brainrepo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/brainrepo"/>
    <language>en</language>
    <item>
      <title>A pseudo imperative approach for react confirmation dialogs</title>
      <dc:creator>BrainRepo</dc:creator>
      <pubDate>Tue, 20 Feb 2024 16:09:08 +0000</pubDate>
      <link>https://forem.com/brainrepo/a-pseudo-imperative-approach-for-react-confirmation-dialogs-3jcn</link>
      <guid>https://forem.com/brainrepo/a-pseudo-imperative-approach-for-react-confirmation-dialogs-3jcn</guid>
      <description>&lt;p&gt;Hello, this is the first technical article I am writing since we started developing fouriviere.io; for more info about the Fourier project, please visit &lt;a href="https://www.fourviere.io"&gt;fourviere.io&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem I want to discuss regards the &lt;strong&gt;confirmation modal&lt;/strong&gt;; we have a few of them in our most complex flows (e.g., feed sync, feed/episode deletion).&lt;/p&gt;

&lt;p&gt;Having a confirmation modal is often a good practice for managing un-revertable or destructive actions, and we adopted it in our critical paths for protecting the user from accidental actions.&lt;/p&gt;

&lt;p&gt;Our frontend is built with React, and one of React's peculiarities is its very declarative approach, an approach that contrasts with the imperative approach of the confirmation modal. Considering this, our initial implementation bypassed the obstacle by effectively circumventing it; in fact, we used the &lt;a href="https://tauri.app/v1/api/js/dialog/#confirm"&gt;&lt;strong&gt;tauri dialog&lt;/strong&gt;&lt;/a&gt; function, which mimics the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm"&gt;web api confirm method&lt;/a&gt; confirm method in a certain way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//...do something&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;confirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This action cannot be reverted. Are you sure?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tauri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;confirmed&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;//...exit&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="c1"&gt;//...continue the action&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is cool because it can be used in complex workflows without fighting with components and complex states; in fact, we don't need to track whether the modal is shown or the confirmation button is pressed.&lt;/p&gt;

&lt;p&gt;However, there is a downside: &lt;strong&gt;the design of this confirmation modal comes from the operating system and does not fit our design styles at all&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  How we solved the problem
&lt;/h1&gt;

&lt;p&gt;First of all, we designed a confirmation modal, for laziness we based our component on the &lt;a href="https://tailwindui.com/components/application-ui/overlays/dialogs"&gt;tailwindui dialog&lt;/a&gt; . &lt;/p&gt;

&lt;p&gt;Here is an oversimplified version. If you want to see the implementation with the tailwind classes, please look at &lt;a href="https://github.com/fourviere/fourviere-podcast/blob/main/packages/ui/lib/dialogs/alert.tsx"&gt;our ui lib&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;okButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cancelButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Alert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;okButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cancelButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;okButton&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cancel&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cancelButton&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we need to display this Alert modal in a &lt;a href="https://react.dev/reference/react-dom/createPortal"&gt;portal&lt;/a&gt; in the most imperative way possible. To do that, we created a hook that exposes an askForConfirmation method that does all the dirty work under the hood.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;&lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Here we will put our implementation&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This hook will return an &lt;code&gt;askForConfirmation&lt;/code&gt; method for being called by the component logic, this method takes a &lt;code&gt;Options&lt;/code&gt; object for defining the modal title, message and icon.&lt;/p&gt;

&lt;p&gt;Now we need to track when modal is displayed and eventually the &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, &lt;code&gt;icon&lt;/code&gt;, the &lt;code&gt;okAction&lt;/code&gt; and the &lt;code&gt;cancelAction&lt;/code&gt;, we define a state for the component, the state can be false or object of type &lt;code&gt;ModalState&lt;/code&gt;, if false the modal is hidden.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ModalState&lt;/span&gt; 
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ModalState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;&lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Here we will put our implementation&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the &lt;code&gt;askForConfirmation&lt;/code&gt; method should set the modal state, let's implement. But we want that does it following an async approach using promises, like that we can call in this way&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//inside the component//&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;//...previous logic&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;continue&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that askForConfirmation should return a promise that is resolved (with true or false) when the ok button is pressed or when the cancel button is pressed; before resolving the promise, the modal is hidden.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ModalState&lt;/span&gt; 
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ModalState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;&lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now stays to implement the display part. This is a hook, and it does not render directly jsx; then we need to find a "sabotage" for managing the render phase. What if the hook returns a function component for rendering it?&lt;/p&gt;

&lt;p&gt;Let's try.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ModalState&lt;/span&gt; 
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ElementType&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ModalState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modals&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;&lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;setModal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
                &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;createPortal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Alert&lt;/span&gt;
                    &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;ExclamationTriangleIcon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;okButton&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"ok"&lt;/span&gt;
                    &lt;span class="na"&gt;cancelButton&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"cancel"&lt;/span&gt;
                    &lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cancel&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;/&amp;gt;,&lt;/span&gt;
                    &lt;span class="nx"&gt;modals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;useConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, our hook returns aside the &lt;code&gt;askForConfirmation&lt;/code&gt;, a function component renderConfirmationModal that displays the modal in the portal (in our case, inside the &lt;code&gt;&amp;lt;div id="modal"&amp;gt;&lt;/code&gt; in the HTML page).&lt;/p&gt;

&lt;p&gt;Now, let's try to use it in a simple component&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SimpleComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;askForConfirmation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Are you sure?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This operation cannot be reverted&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;//do stuff...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;renderConfirmationModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;DO IT/button&amp;gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;After this journey, we have a hook that helps us to have a confirmation modal with a simple api. It is essential to keep simple and reusable parts of the UI; this helps to keep the code readable, and we know how it can become messy our react components. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But keeping things simple needs complex effort.&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Code or no-code, diaries of a half developer half entrepreneur using Directus</title>
      <dc:creator>BrainRepo</dc:creator>
      <pubDate>Sun, 04 Jun 2023 12:01:56 +0000</pubDate>
      <link>https://forem.com/brainrepo/code-or-no-code-diaries-of-a-half-developer-half-entrepreneur-using-directus-3jig</link>
      <guid>https://forem.com/brainrepo/code-or-no-code-diaries-of-a-half-developer-half-entrepreneur-using-directus-3jig</guid>
      <description>&lt;h2&gt;
  
  
  Code or no-code
&lt;/h2&gt;

&lt;p&gt;I have been an entrepreneur for more than one-third of my life; for half of that, I've also been a software engineer.&lt;/p&gt;

&lt;p&gt;Two different identities for the same person can make some target achievements hard to be accomplished.&lt;/p&gt;

&lt;p&gt;Creating side projects or digital products is nearly impossible in this case. My "Prof of concept" folder is full of unfinished projects, all stranded before I even started writing the business logic, and this demonstrates that theory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does this happen?
&lt;/h2&gt;

&lt;p&gt;I spent a long time figuring out the causes and ended up with a simple answer.&lt;/p&gt;

&lt;p&gt;When I start a new project, I want to reach two goals from my two personalities.&lt;br&gt;
The first is to create something that resembles the product I imagined (for fulfilling my entrepreneurial soul)&lt;br&gt;
the second is to learn a new language, framework or technology.&lt;/p&gt;

&lt;p&gt;These two targets rarely blend harmoniously. And it usually happens that I kill the project for one of this two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learning has ended, or my interest in the tech tools I used has waned.&lt;/li&gt;
&lt;li&gt;I picked a technology, language or framework driven by the learning interest rather than the project needs taking me into a situation where I am trying to hammer a nail with a wrench.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What we need from a no-code tool
&lt;/h2&gt;

&lt;p&gt;To avoid this problem, I have to find a pragmatic way to create my POC as fast as possible, focusing on the functional part and letting aside all the skills from my dev side as much as possible.&lt;/p&gt;

&lt;p&gt;Yes, I know you are starting to smell the no-code and codeless fragrance in the air, and I also know that you will begin to say that using a low-code / no-code approach can force me to create a less tailored solution.&lt;/p&gt;

&lt;p&gt;To understand if a low-code approach could be a real option and not just a wishful thought, I had to formalize which were the requirements.&lt;/p&gt;

&lt;p&gt;Let's imagine that I want to create a backend for creating the feed for my podcast, and let's assume that I want to shift this need to make it reusable and multitenant to allow other podcasters to host their podcast on this platform, a sort of alternative to Anchor or Spreaker.&lt;/p&gt;

&lt;h2&gt;
  
  
   Those requirements are:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A rest or graphql crud api to make the interaction from other applications possible&lt;/li&gt;
&lt;li&gt;A simple and extensible CRUD UI for entering data&lt;/li&gt;
&lt;li&gt;A system that handles roles and rights also at the record level, like "this user can see just his records or records where his ID is in the receiver field."&lt;/li&gt;
&lt;li&gt;A system for creating custom endpoints that run custom business logic&lt;/li&gt;
&lt;li&gt;A system for creating workflows based on the time (cron), data entry or changes, etc&lt;/li&gt;
&lt;li&gt;A system for creating custom UI&lt;/li&gt;
&lt;li&gt;A file storage system that manages the data according to roles and rights.&lt;/li&gt;
&lt;li&gt;A user management system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, I can hear your thought, "ehi Mauro, you are looking for the moon", but this is the minimal structure of a minimal SaaS product.&lt;/p&gt;

&lt;p&gt;Let's do a little exercise. Firstly, let's estimate the work needed to implement these features from scratch or with a framework.&lt;/p&gt;

&lt;p&gt;Ok, no matter if you use a fast framework like rails o laravel, just one answer is correct: "too much code, too much time".&lt;/p&gt;

&lt;h2&gt;
  
  
  Directus
&lt;/h2&gt;

&lt;p&gt;After searching for a while, trying different open-source, closed-source, on-premise and "as a service" products, I finally found an open-source solution that fits nearly 100% of my needs.&lt;/p&gt;

&lt;p&gt;Directus has all the requirements mentioned above and more features with a special plus that it has a complete set of possible extensions.&lt;/p&gt;

&lt;p&gt;We can use our developer superpowers.&lt;br&gt;
If we reach the limit of the "out of the box API or UI."&lt;br&gt;
We can extend our instance with custom UIs for fields, list pages, email templates, interfaces and complete custom modules, everything possible just by creating a simple package that uses Vue js.&lt;/p&gt;

&lt;p&gt;We can also extend the backend part by writing simple js or typescript code creating knexjs database migrations, custom hooks and endpoints.&lt;/p&gt;

&lt;p&gt;With Directus, I felt a new feeling. Finally, being a developer could help my entrepreneurial desires without introducing too much complexity or time needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limits
&lt;/h2&gt;

&lt;p&gt;Ok, All that glitters is not gold.&lt;br&gt;
Until now, I spotted two limits:&lt;br&gt;
A vuejs development experience is not suitable for me. Compared to react, it is more verbose and less ergonomic.&lt;br&gt;
I wouldn't say I like express js. I cheer for fastify.&lt;/p&gt;

&lt;p&gt;Do you feel them silly? 😂. I still am a developer, and cheering is our favourite sport.&lt;/p&gt;

&lt;p&gt;Jokes aside, there is one big limit that Directus shows after a while you use it. So if you want to do something more complex than classic crud or if you want to create your extension, you need to rely on complete documentation.&lt;br&gt;
Currently, the extensions docs miss some details in the extensions topic, to understand how things work, I dug into the source.&lt;br&gt;
&lt;strong&gt;Since Directus is opensource, let's improve the docs together!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ps. Here are the directus website and docs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://directus.io/"&gt;https://directus.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.directus.io/getting-started/introduction.html"&gt;https://docs.directus.io/getting-started/introduction.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nocode</category>
      <category>lowcode</category>
      <category>code</category>
    </item>
    <item>
      <title>I am tired of hearing banalities about remote working</title>
      <dc:creator>BrainRepo</dc:creator>
      <pubDate>Sun, 04 Jun 2023 11:24:41 +0000</pubDate>
      <link>https://forem.com/brainrepo/i-am-tired-of-hearing-banalities-about-remote-working-3men</link>
      <guid>https://forem.com/brainrepo/i-am-tired-of-hearing-banalities-about-remote-working-3men</guid>
      <description>&lt;p&gt;&lt;strong&gt;This article was previously hosted on brainrepo.dev and was written on January 30, 2023, at 03:57 PM.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All opinions I express here are my ones.&lt;/em&gt;*&lt;/p&gt;

&lt;p&gt;As you know, I’ve been working for a full-remote tech company, and I love to do it!&lt;/p&gt;

&lt;p&gt;I explain and share my opinion very calmly and moderately, but when I read statements that trivialize crucial topics, I lose self-control and rage.&lt;/p&gt;

&lt;p&gt;That’s what happened a few days ago reading a post on LinkedIn.&lt;/p&gt;

&lt;p&gt;But let’s see those bullshit one by one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Come to think of it: the world is not built by people teleworking…&lt;br&gt;
We want to invent and experiment with new ways of working.&lt;br&gt;
Because, yes, the world is changing…&lt;br&gt;
We want to train young people in our business on the ground.&lt;br&gt;
We want to be there for our customers.&lt;br&gt;
We want to share technical opinions in an open space that may be a little noisy but is full of life…&lt;br&gt;
We want to shake hands.&lt;br&gt;&lt;br&gt;
We want to laugh at the coffee machine.&lt;br&gt;
We don’t want this “trend” that isolates people.&lt;br&gt;
It is a sad fate to don’t leave your home anymore!&lt;br&gt;
Locked up at home… without an electronic bracelet… whatever 🤔…&lt;br&gt;
So, yes, once again, I may push away the “charentaise” sellers and the “pilou pilou pyjama” suppliers.&lt;br&gt;
We at &lt;strong&gt;****&lt;/strong&gt; are going back to real life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And if you like living into cloistering, ordering online and living as an avatar in the metaverse, I think we’ll never meet, and that’s certainly not a bad thing!&lt;/p&gt;

&lt;p&gt;Ok, firstly, a deep breath,&lt;/p&gt;

&lt;p&gt;the world is changing, and how people interact also, I am not a 100% digital life fan, but I am for a good balance between the digital and physical parts. As you see, I don’t speak about real life because real life also contains a digital side!&lt;/p&gt;

&lt;p&gt;“We want to be there for our customers”&lt;/p&gt;

&lt;p&gt;what does it mean? Your customer needs your physical presence. Why? What can your body give more to your customer (😂)?&lt;/p&gt;

&lt;p&gt;I think your customer prefers your attention, sensitivity, patience, expertise, pragmatism and effectiveness.&lt;/p&gt;

&lt;p&gt;We can give all things with honest communication, commitment and empathy in front of a webcam (mandatorily on) or with a well-written email!&lt;/p&gt;

&lt;p&gt;“We want to share technical opinions in an open space that may be a little noisy but is full of life.”&lt;/p&gt;

&lt;p&gt;Hei man, if you would see our slack channels, where hundreds of people share opinions, experiences and their pets’ photos, you would understand. And you know, being a fully remote company allows us to amplify that because, in the channel, you see the true diversity, people from different places, with various religions or gender speaking together with respect, pleasure and open-mindedness.&lt;/p&gt;

&lt;p&gt;I was born in a little village in the centre of Sardinia. Say to me when I could have had such an opportunity! Thanks to remote working, I have this opportunity and defend it with all my might!&lt;/p&gt;

&lt;p&gt;Speaking about the opportunity, in a world without remote working, how a guy/girl can work for an international company and be part of a global impact without living in his/her hometown? This has a significant effect, you know? Little villages are dying, and people following the occasion are sacrificing their quality of life!&lt;/p&gt;

&lt;p&gt;“We want to shake hands. We want to laugh at the coffee machine.”&lt;/p&gt;

&lt;p&gt;How strong are the relations constructed in front of the coffee machine?&lt;/p&gt;

&lt;p&gt;Quality rather than quantity determines the power of our relationships.&lt;/p&gt;

&lt;p&gt;I am just coming back from a very intense company retirement with activities that helped me reach my limits, and I am pretty sure that the experiences I shared with my colleagues are stronger than years of coffee machine times! I can call them friends after seeing them just one time!&lt;/p&gt;

&lt;p&gt;These shared experiences are necessary for professional remote working and not only that.&lt;/p&gt;

&lt;p&gt;We at &lt;strong&gt;****&lt;/strong&gt; are going back to real life.&lt;/p&gt;

&lt;p&gt;And if you like living into cloistering, ordering online and living as an avatar in the metaverse, I think we’ll never meet, and that’s certainly not a bad thing!&lt;/p&gt;

&lt;p&gt;I am not isolated. I am remote and connected to the world.&lt;/p&gt;

&lt;p&gt;If I am living with an electronic bracelet, I am happy to have it because my jail is the entire world!&lt;/p&gt;

&lt;p&gt;Ps: There are another thousand good reasons why remote working well-made is a good thing, but I am nervous, tired, and at midnight. I’m going to bed. See you!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What would it be like if Italo Calvino and Sun Tzu explained refactoring?</title>
      <dc:creator>BrainRepo</dc:creator>
      <pubDate>Sun, 04 Jun 2023 11:18:51 +0000</pubDate>
      <link>https://forem.com/brainrepo/what-would-it-be-like-if-italo-calvino-and-sun-tzu-explained-refactoring-32kl</link>
      <guid>https://forem.com/brainrepo/what-would-it-be-like-if-italo-calvino-and-sun-tzu-explained-refactoring-32kl</guid>
      <description>&lt;p&gt;&lt;strong&gt;This article was previously hosted on brainrepo.dev and was written on February 19, 2023, at 03:57 PM.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cities grow, cities evolve, cities have parts that simply die&lt;br&gt;
while other parts flourish; each city has to be renewed in order&lt;br&gt;
to meet the needs of its populace… Software-intensive systems&lt;br&gt;
are like that. - Grady Booch (UML Inventor)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The day has flown by quickly, and I have a headache.&lt;/p&gt;

&lt;p&gt;I spent the day refactoring the code. Refactoring is not a simple task - there are many things to keep in mind and many things to discover along the way.&lt;/p&gt;

&lt;p&gt;Now is the time to relax and reread a beautiful book I read it many years ago.&lt;br&gt;
"Invisible Cities" by Italo Calvino.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The city of Leonia refashions itself every day:&lt;br&gt;
every morning the people wake between fresh sheets,&lt;br&gt;
wash with just-unwrapped cakes of soap, wear&lt;br&gt;
brand-new clothing, take from the latest model&lt;br&gt;
refrigerator still unopened tins, listening to the&lt;br&gt;
last-minute jingles from the most up-to-date radio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TsKThFW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xfii1j94g0oce8fj96v.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TsKThFW9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xfii1j94g0oce8fj96v.jpeg" alt="Leonia, Anan001 - devianart" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I read this, I'm reminded of Refactoring and all the conflicts and pains that come with it.&lt;/p&gt;

&lt;p&gt;The Refactoring approach works similarly to Rudolph Giuliani's crime reduction strategy in New York City in the 90s.&lt;/p&gt;

&lt;p&gt;Clean up the city, and the city will clean itself up.&lt;/p&gt;

&lt;p&gt;Even though these simple words may sound like a magic formula, we have no magic wand. They hide commitment and dedication to the code/city we want to carry into the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is refactoring?
&lt;/h2&gt;

&lt;p&gt;Refactoring is an internal change or evolution (in the Darwinian sense) that does not alter the code's external behaviour and aims to improve the characteristics that make our code resilient, I am not refering to the bugfixing activity, but rather all the action for increase maintainability, performance and reduce the complexity.&lt;/p&gt;

&lt;p&gt;It is said that to develop a good habit, we must repeat it, repeat it again, and repeat it some more, and the same goes for refactoring.&lt;/p&gt;

&lt;p&gt;Refactoring shouldn't be a one off activity. We should create a routine following the infinite cycle of Test-Driven Development (TDD); write the test, develop the micro-functionality on the fly, just to make it work, and then refactorone off, just cleaning and refining what done.&lt;/p&gt;

&lt;p&gt;Every time we refactor, we must do it in the best way possible, constantly guided by pragmatism (I come back to this issue later), in other words, organizing everything in order to complete the activity in the available timeframe.&lt;/p&gt;

&lt;p&gt;And then, once again, a red test, a new feature, and refactoring...&lt;/p&gt;

&lt;h2&gt;
  
  
  Tactical and Strategic Programming
&lt;/h2&gt;

&lt;p&gt;The first step to understanding refactoring is to realize there are two ways of programming: tactical and strategic.&lt;/p&gt;

&lt;p&gt;Kent Beck uses the metaphor of two hats, one for writing code and the other for refactoring.&lt;/p&gt;

&lt;p&gt;Whenever we write code, we put ourselves in the shoes of bricklayers -- the professionals who, in a &lt;strong&gt;tactical&lt;/strong&gt; way, create something "that works" in the shortest time possible without being concerned about the complexity increase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--41kZWLXD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/op83j0shi66w4g5a9qhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--41kZWLXD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/op83j0shi66w4g5a9qhj.png" alt="https://www.deviantart.com/goombablood/art/When-two-hats-aren-t-enough-863446109" width="480" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the other hand, the &lt;strong&gt;strategic&lt;/strong&gt; hat resembles the engineer's point of view and presupposes a holistic vision of the context. His priorities are to reduce or at least contain the system's complexity, even with a medium-long-term perspective.&lt;/p&gt;

&lt;p&gt;Therefore, one of the engineer's tasks is to establish the goal of refactoring. To be meaningful and beneficial, the &lt;strong&gt;refactoring must always have a reason and a goal to achieve. This is the task from the engineer's perspective.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have always said that a developer must be a monster with two personalities (that's why we are often thought of as crazy). We must learn to switch from one hat to the other quickly and with a good rhythm. In general, the more frequently we bounce between the two personalities, the better the quality of our code.&lt;/p&gt;

&lt;p&gt;Developing a new feature or fixing a bug often increases coupling and complexity, sending style and coherence into hell. This is where we need to make a leap towards strategic thinking.&lt;/p&gt;

&lt;p&gt;In "The Art of War", Sun Tzu says that the ideal future vision must influence present actions.&lt;/p&gt;

&lt;p&gt;To achieve victory, the commander must know whether the battle he is fighting today will lead him there.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Do not move unless you see an advantage; do not use your troops unless something is to be gained."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately, the products we develop today often do not envision the future clearly. Our market moves quickly and is infamously mutable, so how can we guide our everyday work?&lt;/p&gt;

&lt;p&gt;🧭 We can do it guided by &lt;strong&gt;Values&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistency
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;On the sidewalks, encased in spotless plastic bags,&lt;br&gt;
the remains of yesterday's Leonia await the garbage&lt;br&gt;
truck. Not only squeezed tubes of toothpaste,&lt;br&gt;
blown-out light bulbs, newspapers, containers,&lt;br&gt;
wrappings, but also boilers, encyclopedias, pianos,&lt;br&gt;
procelain dinner services. It is not so much by the&lt;br&gt;
things that each day are manufactured, sold, bought&lt;br&gt;
that you can measure Leonia's opulence, but rather&lt;br&gt;
by the things that each day are thrown out to make&lt;br&gt;
room for the new.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To understand values, we must make our way through the garbage of Leonia. The first feeling we experience is disorientation. When we impact with this sensation, we notice the need for an essential value, a compass that we can call &lt;strong&gt;consistency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The need for consistency usually arises when we sit behind our desks and face the monitor. Everything looks calm, but this is when we realize that our code looks alien to us.&lt;/p&gt;

&lt;p&gt;Our efforts to understand become more and more, and we spend considerable time doing so.&lt;br&gt;
Frustration accumulates when the code is not designed to accommodate the modification we want, letting us with just the dream of an ideal world where the quality of our codebase equals what we imagined during the design phase.&lt;/p&gt;

&lt;p&gt;In this situation, a dangerous driver has fueled: &lt;strong&gt;fear&lt;/strong&gt;. TDD helps us not be overwhelmed by this feeling, at least eliminating the uncertainty of what will happen once the modification is applied. But is it enough?&lt;br&gt;
In a refactoring context where fear is present, refactoring turns into many little quick fixes. Small interventions that are driven by the intent to be less impactful as possible to avoid breaking things. Sounds scary, but here is a situation where a slight change in the code can have a ripple effect. Instead of bringing improvements, acting this way increases our code complexity, inconsistency, and instability. The code will need further refactoring again, triggering a negative spiral.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the result: the more Leonia expels goods,&lt;br&gt;
the more it accumulates them; the scales of its past&lt;br&gt;
are soldered into a cuirass that cannot be removed.&lt;br&gt;
As the city is renewed each day, it preserves all of itself&lt;br&gt;
in its only definitive form: yesterday's sweepings&lt;br&gt;
piled up on the sweepings of the day before yesterday&lt;br&gt;
and of all its days and years and decades.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This happens purely because we are not comfortable with our code. But why?&lt;/p&gt;

&lt;p&gt;Because conventions help us orient ourselves and show us the way. What would a city be like if every neighbourhood had different street signs?&lt;/p&gt;

&lt;p&gt;Consistency allows us to learn things in one place and reuse/recognize them everywhere.&lt;/p&gt;

&lt;p&gt;Knowing the rules, we no longer need to rack our brains looking for patterns or making wrong assumptions.&lt;/p&gt;

&lt;p&gt;Because of that, when we learn something that is not obvious from our code, we need to memorize it. But, unfortunately, our memorization ability is finite (mine is very limited), and, like the ancient scribes, when we achieve to solve the puzzle, we need to formalize our understood bringing it out from our minds and putting it into code (I mean not only on writing code but perhaps removing it is more important 😀).&lt;/p&gt;

&lt;h2&gt;
  
  
  The pitfalls in the search for consistency
&lt;/h2&gt;

&lt;p&gt;The need for consistency leads us to a compulsive and often unconscious search, and here are two everyday actions that arise in this situation.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;comprehension refactoring&lt;/strong&gt; and the &lt;strong&gt;aesthetic lifting&lt;/strong&gt; (Yuch refactoring).&lt;/p&gt;

&lt;p&gt;The violent attack of comprehension refactoring is activated when we don't understand what's happening. When we are entangled in a dense maze of classes and functions, and we don't know why they are there and what they do.&lt;/p&gt;

&lt;p&gt;As Martin Fowler would say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After all, I would say that our code is not a mystery novel.&lt;/p&gt;

&lt;p&gt;The other trap lies behind the concept of aesthetic refactoring of our code.&lt;br&gt;
When pronouncing “What is this rubbish, and who wrote it?” is the instant just before a lifting refactoring.&lt;/p&gt;

&lt;p&gt;We, developers, dislike ugly or unfashionable code, and when we see something that does not adhere to our own standards of beauty, we refactor it.&lt;/p&gt;

&lt;p&gt;Why do these two refactoring drivers hide a pitfall?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The desire to throw everything away and rewrite everything from scratch is just around the corner, and we often do it without worrying too much about the sustainability of our decision.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And so, to quote Calvino...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;he greater its height grows, the more the danger&lt;br&gt;
of a landslide looms: a tin can, an old tire, an unraveled&lt;br&gt;
wine Bask, if it rolls toward Leonia, is enough&lt;br&gt;
to bring with it an avalanche of unmated shoes, calendars&lt;br&gt;
of bygone years, withered Bowers, submerging the city in&lt;br&gt;
its own past, which it had tried in&lt;br&gt;
vain to reject, mingling with the ~t of the neighboring cities,&lt;br&gt;
finally clean. A cataclysm will Batten&lt;br&gt;
the sordid mountain range, canceling every trace of&lt;br&gt;
the metropolis always dressed in new clothes. In the&lt;br&gt;
nearby cities they are all ready, waiting with bulldozers to&lt;br&gt;
Batten the terrain, to push into the new&lt;br&gt;
territory, expand, and drive the new street cleaners&lt;br&gt;
still farther out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By rewriting everything, we &lt;strong&gt;endanger our business&lt;/strong&gt;. Our decision to rewrite code is often driven by an incomplete analysis of our codebase caused often by an incomplete/limited vision given by our current perspective. When we start the rewrite, we must reconsider all of the decisions we have taken over weeks, months, and years, &lt;strong&gt;facing a bill we cannot afford&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rewriting everything means redoing the work that has brought us to this point, including the team discussions. We also need to do new training about the new conventions.&lt;/p&gt;

&lt;h2&gt;
  
  
  And then?
&lt;/h2&gt;

&lt;p&gt;So, we have two paths to follow: accepting the compulsive refactoring cycle or recognizing what in our code is worth refactoring regardless of trends and/or compulsive attacks.&lt;/p&gt;

&lt;p&gt;This is not an effortless decision, as it presupposes the development of a pragmatic awareness that leads to accepting imperfection and finding a balance between consistency and innovation.&lt;/p&gt;

&lt;p&gt;To do this, it is essential to start with four questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do I have enough information to justify my action (whether it is a consistency break or innovation introduction),&lt;/li&gt;
&lt;li&gt;Wasn’t this information available in the design phase? And why was it not done that way if it was available in the design phase?&lt;/li&gt;
&lt;li&gt;Am I breaking conventions? How much does this cost me regarding training for people involved in the codebase?&lt;/li&gt;
&lt;li&gt;Does the change I am introducing really generate value in terms of maintenance from a product perspective?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Answering these questions will make it easy to see some considerations emerge.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactoring the code complex areas is just the refactoring that makes sense. On the simple and understandable parts is often an effort waste.&lt;/li&gt;
&lt;li&gt;When estimating refactoring, we must always consider the full scope of the project, including edge cases. Often, the hidden costs and efforts are there.&lt;/li&gt;
&lt;li&gt;Reconsidering conventions can often become a waste of time. New conventions can improve our code, but sometimes distributing knowledge is a hidden heavy cost.&lt;/li&gt;
&lt;li&gt;When making decisions regarding refactoring, it is necessary to use a coordinated approach, involving all the stakeholders, sharing ownership and documenting decisions with ADR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From what I have written so far, it might seem that I am not a fan of refactoring, but I like it.&lt;/p&gt;

&lt;p&gt;I think that refactoring should be estimated implicitly in the project plan and diluted in the work of everyday life, avoiding the “formal refactoring moment” approach done to justify the "not done" in everyday work.&lt;/p&gt;

&lt;p&gt;Refactoring should be automatic and probably should not have a name because it is implicit in the act of writing code (giving it a name mentally tends to purge it from the act of programming).&lt;/p&gt;

&lt;p&gt;Refactoring should start by accepting imperfection, like in the Wabi-sabi Japanese philosophy. That vision or aesthetic is based on accepting the transience and imperfection of things. That vision of "imperfect, impermanent, and incomplete beauty" is typical of the Buddhist world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TnPQ_Mfo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9t1g5o68qb9sk9kiro9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TnPQ_Mfo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t9t1g5o68qb9sk9kiro9.jpeg" alt="https://www.deviantart.com/elorie-portrait/art/Kintsugi-cap-3-650928093" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So when can see refactoring as an evolution of conscious repair actions, which make our code tell a coherent story written over time, step by step.&lt;/p&gt;

&lt;p&gt;Romantically, I like to imagine the value of code memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Restoring code not to a state of newness but also to a state that keeps the memory like done in Kintsugi, the art of repairing ceramics with gold.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calvino describes this feeling and idea better than I in the final part of Invisible Cities when he says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The inferno of the living is not something that will be; if there is one, it is what is already here, the inferno where we live every day, that we form by being together.&lt;br&gt;
There are two ways to escape suffering it. The first is easy for many: accept the inferno and become such a part of it that you can no longer see it. The second is risky and demands constant vigilance and apprehension: seek and learn to recognize who and what, in the midst of inferno, are not inferno, then make them endure, give them space.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I let you some links if you wan't to read more about Italo Calvino or Sun Tzu&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;I also recorded one pocast episode / talk about it, but it is in Italian. If you come from the Dante's land you can enjoy it :D&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gitbar.it/episodes/ep52-la-programmazione-e-il-refactoring-secondo-italo-calvino"&gt;https://www.gitbar.it/episodes/ep52-la-programmazione-e-il-refactoring-secondo-italo-calvino&lt;/a&gt;&lt;/p&gt;

</description>
      <category>refactoring</category>
      <category>bestpractices</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I converted a podcast into a knowledge base using Orama search and OpenAI whisper and Astro</title>
      <dc:creator>BrainRepo</dc:creator>
      <pubDate>Tue, 23 May 2023 10:08:24 +0000</pubDate>
      <link>https://forem.com/brainrepo/how-i-converted-a-podcast-into-a-knowledge-base-using-orama-search-and-openai-whisper-2aca</link>
      <guid>https://forem.com/brainrepo/how-i-converted-a-podcast-into-a-knowledge-base-using-orama-search-and-openai-whisper-2aca</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/o4ybKOeQ4Xc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As many of you know, I have been hosting a podcast for the last three and a half years. It is one of the most exciting experiences of my life. I have produced approximately 200 hours of audio content in all these years. &lt;/p&gt;

&lt;p&gt;The audio content has a drawback; if you want to search for something that was said, you often have to listen to hours and hours of old episodes without reaching the searched point.&lt;/p&gt;

&lt;p&gt;How to solve this problem?&lt;/p&gt;

&lt;h2&gt;
  
  
  Transcript
&lt;/h2&gt;

&lt;p&gt;The first step is to transcribe the episodes. Since the beginning, I have implemented a simple pipeline to transcribe each episode. &lt;/p&gt;

&lt;p&gt;It turned out to be a total failure! The transcriptions were based on AWS Transcribe, and the service couldn't transcribe Italian audio correctly, perhaps due to the presence of technical English words or the remarkable Sardinian accent. &lt;/p&gt;

&lt;p&gt;The outcome was terrible, it was impossible to read and understand the meaning, and they were not usable for my primary purpose. Aside from that, it also had a cost, each transcription was around 1 euro, and despite the low price, it was an absolute waste of money.&lt;/p&gt;

&lt;p&gt;After one year, I stopped using the lambdas and decided not to transcribe the episodes anymore.&lt;/p&gt;

&lt;p&gt;Also, the wise man retraces his steps, and who am I to not review my decisions?&lt;/p&gt;

&lt;p&gt;Reviewing the decision is an outstanding practice, and doing it when the context changes could help us to stay tuned with the world around us and catch opportunities.&lt;/p&gt;

&lt;p&gt;Since Open Ai started releasing its products, our industry was swept into a whirlwind of astonishment; chat GPT, copilot, and DALL•E were perceived as masterpieces, but another service caught my attention.&lt;/p&gt;

&lt;p&gt;Whisper, as its name suggests, arrived without making much noise. While all the attention was on ChatGPT, Whisper was exceptionally interesting. Its quality, compared to other transcription services, is remarkable. It performs excellently in Italian, accurately recognising English words and technical jargon. I have never seen such precision before. Moreover, there is another non-trivial aspect—it is open source and released under the MIT license!&lt;/p&gt;

&lt;p&gt;After conducting a test, I quickly embraced Whisper to transcribe the episodes. At first, I was tempted to set up a machine on AWS to run the entire process in the cloud. However, Whisper requires a massive amount of resources and time. Ultimately, I chose to run it on my gaming machine, which has been dormant for a while. My desktop computer, equipped with a GTX 3060, was the perfect candidate to put it to the test, especially after I stopped playing video games.&lt;/p&gt;

&lt;p&gt;Whisper offers different pre-trained models, ranging from small to large. The largest one, which provides the best quality but is also the slowest, can utilise the mathematical capabilities of the GPU.&lt;/p&gt;

&lt;p&gt;Since I am not a Python developer and PyTorch is unfamiliar to me, starting from scratch to implement the transcription script was nearly impossible.&lt;/p&gt;

&lt;p&gt;Thankfully, a simple Docker image came to my rescue. This container simplifies all the steps and provides a REST API directly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ahmetoner/whisper-asr-webservice" rel="noopener noreferrer"&gt;https://github.com/ahmetoner/whisper-asr-webservice&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, it is enough to navigate to the web port exposed by the container to reach the swagger ui. From the Swagger UI, select the file, select the language (in my case, Italian), and wait around 30 minutes. Each episode is one and a half hours long, so Whisper needs quite a bit of time for transcribing. In the end, we will receive a well-structured JSON file containing the transcriptions with time references.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfcnm7duv6gxfefwexwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfcnm7duv6gxfefwexwz.png" alt="The swagger interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cool, but now it's time to play with the code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Make it searchable
&lt;/h2&gt;

&lt;p&gt;With Whisper, I have completed the first half of the problem. Now it's time to discuss how to implement the search functionality.&lt;/p&gt;

&lt;p&gt;Whisper can export in multiple formats, including TXT, VTT, SRT, TSV, and JSON.&lt;/p&gt;

&lt;p&gt;In my case, I will be using the JSON data format. This format contains both the raw translated text and the time-coded text. The raw translated text is displayed on the episode page and is crucial for SEO purposes. The second part of the implementation revolves around the search functionality, which is one of the main pillars of this project.&lt;/p&gt;

&lt;p&gt;The search process is fairly straightforward. There will be an input box where users can enter the words they wish to search for. &lt;/p&gt;

&lt;p&gt;After submitting the search query, a list of audio samples that match the searched terms will be displayed. &lt;/p&gt;

&lt;p&gt;The episode will be played by clicking on the "play" button next to each text slice, starting from when the word is pronounced.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw39ds2a1boaiysfxgqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw39ds2a1boaiysfxgqe.png" alt="The gitbar search feature"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Gitbar website has no backend; it is entirely static and built using Astro, an excellent framework.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/brainrepo/gitbar-2023" rel="noopener noreferrer"&gt;https://github.com/brainrepo/gitbar-2023&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How to manage the search feature? Should I install Elasticsearch? How much will it cost? Or should I consider using Algolia? &lt;br&gt;
These questions arose as I started implementing the feature.&lt;/p&gt;

&lt;p&gt;From the beginning, using Elasticsearch was excluded as an option. Managing an Elasticsearch instance is not trivial, as it requires a server or computational capabilities. Similarly, using Algolia incurs additional costs, and since we rely on donations to support Gitbar's expenses, we need to minimise the expenditures.&lt;/p&gt;

&lt;p&gt;Therefore, I needed to find an alternative solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38d1jflu0rqb9okie7zu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F38d1jflu0rqb9okie7zu.jpeg" alt="Orama search logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have been following Michele's project, Orama Search, since its inception, and I believe he, Paolo, Angela, and their "crime partners" are doing incredible work with it.&lt;/p&gt;

&lt;p&gt;If JavaScript has democratised software development, I would say that Orama Search (also known as Lyra for nostalgic folks like me) has done the same for the search experience.&lt;/p&gt;

&lt;p&gt;Initially, JavaScript may seem limiting, but thanks to it, we can run Orama Search everywhere, from the client to the server. It's truly amazing!&lt;/p&gt;

&lt;p&gt;Another appealing aspect of Orama is its immutable nature, which makes it the perfect fit for my use case.&lt;/p&gt;

&lt;p&gt;Since the Gitbar website is statically generated, it is not an issue for me to build the search index during the page generation process and share it as a simple JSON file.&lt;/p&gt;

&lt;p&gt;To accomplish that, I created an Astro plugin inspired by the official one.&lt;/p&gt;

&lt;p&gt;Now, let's dive into the details of what I have implemented.&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating an Astro Plugin for Orama Search
&lt;/h2&gt;

&lt;p&gt;Orama Search provides built-in support for Astro. It takes the generated files of the website and creates an index or database from the content within the HTML pages. However, my use case had specific requirements that differed from the common ones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk02om15m9ybz4ai30tv5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk02om15m9ybz4ai30tv5.jpeg" alt="Astro"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can refer to the &lt;strong&gt;&lt;a href="https://docs.oramasearch.com/plugins/plugin-astro" rel="noopener noreferrer"&gt;Astro plugin documentation for Orama&lt;/a&gt;&lt;/strong&gt; for more information.&lt;/p&gt;

&lt;p&gt;To meet my specific needs, I had to index a particular data structure that included the following fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;text&lt;/code&gt;&lt;/strong&gt;: The transcribed fragment, usually consisting of 10-15 words.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;title&lt;/code&gt;&lt;/strong&gt;: The episode title.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;from&lt;/code&gt;&lt;/strong&gt;: The timestamp indicating when the words are pronounced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;episodePath&lt;/code&gt;&lt;/strong&gt;: The path of the episode page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given this requirement, I had to create a plugin from scratch to support it.&lt;/p&gt;

&lt;p&gt;Astro provides a plugin API that allows us to extend its capabilities. It's important to note that the plugin API is relatively low-level. While it grants access to many internal details, it also requires caution when making changes to avoid unintended consequences.&lt;/p&gt;

&lt;p&gt;Now, let's go through the steps involved in creating the plugin.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Initial Setup:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To start, create a new folder in the root directory of your project called &lt;strong&gt;&lt;code&gt;/plugins&lt;/code&gt;&lt;/strong&gt;. This folder will hold all the plugins for this project. Each Astro plugin is a JavaScript (or TypeScript) file that exports a single function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GITBAR-ASTRO-SEARCH&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;astro:server:start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;initDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;astro:build:done&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;initDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prod&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Astro's core functionalities can be extended using hooks, which allow us to run custom JavaScript code at specific moments in Astro's lifecycle. In this case, we want to extend two pivotal moments: the server starting phase and the build done phase, when the website is fully built.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;astro:server:start:&lt;/strong&gt; Since Gitbar is a static website and will be served by Netlify servers, we don't require a Node server to run it. However, during the development environment, we want the plugin to build the Orama database for us to use in the development process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;astro:build:done:&lt;/strong&gt; We use this hook to build the production database. When we release the website, along with the static pages, we also release a JSON file that contains a serialized **Orama database.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Data Preparation and Ingestion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To prepare the data for seeding the Orama database, I followed a multi-step process. Here's a breakdown of the steps you took:&lt;/p&gt;

&lt;p&gt;Fetch the episodes from the podcast feed using the &lt;strong&gt;&lt;code&gt;@podverse/podcast-feed-parser&lt;/code&gt;&lt;/strong&gt; library. This allowed me to retrieve the necessary episode data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;episodes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPodcastFeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastFeed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Iterate over the list of episodes and check if there is a corresponding translation file in the &lt;strong&gt;&lt;code&gt;transcriptions&lt;/code&gt;&lt;/strong&gt; folder. You searched for a file with the episode number as the filename.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;episodes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPodcastFeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;podcastURL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;episodeSegments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;episodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;episodeNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractEpisodeNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`../transcriptions/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;episodeNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.json`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;mp3url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enclosure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}));&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Transcription &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;episodeNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; not found`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;episodeSegments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;segmentsToInsert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After obtaining the segments for each episode, I flattened them into a single array that contains all the segments of all the episodes.&lt;/p&gt;

&lt;p&gt;After that, I created the Orama database by calling the &lt;strong&gt;&lt;code&gt;create&lt;/code&gt;&lt;/strong&gt; function providing the desired schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mp3url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To efficiently insert the segments into the Orama database, I divided them into chunks of 500 units and used the &lt;strong&gt;&lt;code&gt;insertMultiple&lt;/code&gt;&lt;/strong&gt; function for batch insertion.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;insertMultiple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;episodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, to complete the plugin, I serialised the database to a JSON file. This allowed me to share the database as a simple JSON file.&lt;/p&gt;

&lt;p&gt;With these steps, I am able to prepare and ingest the necessary data into the Orama search index, using the appropriate schema and chunking techniques to optimise performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Search component
&lt;/h2&gt;

&lt;p&gt;Now is the time to come out from the shadows and create the components for our search form. Since Astro supports React components, let's write our search component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will skip some parts to keep the focus on the interesting ones.&lt;/p&gt;

&lt;p&gt;The first thing I want to do is fetch the Orama database that we built earlier from the network. I want to do this during the mounting phase of the component.&lt;/p&gt;

&lt;p&gt;I'll use a &lt;strong&gt;&lt;code&gt;useEffect&lt;/code&gt;&lt;/strong&gt; hook where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I initialise the Orama instance with the same schema used before.&lt;/li&gt;
&lt;li&gt;I load the database file and track the loading state to disable the search UI during the loading process.&lt;/li&gt;
&lt;li&gt;I load the fetched data into the Orama instance.&lt;/li&gt;
&lt;li&gt;I update the DB state to make the Orama instance available to the component.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@orama/orama&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// State that holds the database&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDB&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// State that holds the loading status&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;mp3url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/in_episode.db.json`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we need to create our search function, which we'll call when there is a change in the search field input.&lt;/p&gt;

&lt;p&gt;To avoid creating a new &lt;code&gt;find&lt;/code&gt; function with every rendering, we'll use the &lt;code&gt;useCallback&lt;/code&gt; hook to cache it and update it when &lt;code&gt;DB&lt;/code&gt; or &lt;code&gt;setResults&lt;/code&gt; changes.&lt;/p&gt;

&lt;p&gt;The rest of the function calls Orama's search function with the search term and runs the search on all properties, retrieving the first 100 results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;find&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nf"&gt;setResults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setResults&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all that's left is to attach this function to an input field change event, and we're done!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"bg-transparent w-full text-white p-6 text-2xl outline-yellow-300 outline-3 placeholder:text-yellow-300"&lt;/span&gt;
    &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Search..."&lt;/span&gt;
    &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The audio player features are beyond the scope of this article. Let me know if you would like me to write an article on that.&lt;/p&gt;

&lt;p&gt;I intentionally left out some other implementation details. If you want a running code example, take a look at &lt;strong&gt;&lt;a href="https://github.com/brainrepo/gitbar-2023/blob/main/src/plugins/lyra_in_episode.ts" rel="noopener noreferrer"&gt;https://github.com/brainrepo/gitbar-2023/blob/main/src/plugins/lyra_in_episode.ts&lt;/a&gt;&lt;/strong&gt; for the database creation and &lt;strong&gt;&lt;a href="https://github.com/brainrepo/gitbar-2023/blob/main/src/components/searchAdvanced.tsx" rel="noopener noreferrer"&gt;https://github.com/brainrepo/gitbar-2023/blob/main/src/components/searchAdvanced.tsx&lt;/a&gt;&lt;/strong&gt; for the frontend JSX code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The limits
&lt;/h2&gt;

&lt;p&gt;Currently the search feature is in production on this &lt;a href="https://www.gitbar.it/advanced-search" rel="noopener noreferrer"&gt;url&lt;/a&gt;, but if you check the network inspector you will see that the Orama database size is more the 40MB, note that not all the episode are indexed, the transcription process takes lots of time and I transcribed and indexed from the episonde n*130 to the number 156.&lt;/p&gt;

&lt;p&gt;The size is not negligible, and I expect that the size of the database can reach 200MB pretty soon.&lt;/p&gt;

&lt;p&gt;Botstrapping a nodejs server for running it seems the most reasonable way to solve the problem, but I don’t want to do it than I need a plan B.&lt;/p&gt;

&lt;h2&gt;
  
  
  The B Plan
&lt;/h2&gt;

&lt;p&gt;My Plan B has two levels:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first solution is very straightforward. The JavaScript ecosystem offers some fantastic libraries that can assist with GZIP compression. It appears that the Netlify servers don't handle compression, so I can leverage libraries such as &lt;strong&gt;&lt;code&gt;pako&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;tiny-inflate&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;uzip.js&lt;/code&gt;&lt;/strong&gt;, or &lt;strong&gt;&lt;code&gt;fflate&lt;/code&gt;&lt;/strong&gt; to achieve this goal. I conducted some tests, and the compressed database size was reduced to just 10% of the original size. 
Implementing this solution requires only a few lines of code, specifically less than 4. 
By incorporating this solution, I can easily handle up to 300 episodes with sustainable download times. Considering that I have recorded around 160 episodes in the past three and a half years, I can sleep soundly because I have ample time ahead.&lt;/li&gt;
&lt;li&gt;Whenever I encounter an upper limit, I usually engage in a mental exercise to find a workaround. What if I group the episodes into chunks of 10 or 20 elements and create an Orama database for each group? Furthermore, what if I begin my search with the most recent episodes and, once I have fetched and searched within the first group, I proceed to the older databases until the result limit is reached? This approach would compel the results to be sorted by date (which could even be considered a feature), and the sequential style of this search feature prevents the need to download all the databases in advance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  There is always a C Plan
&lt;/h2&gt;

&lt;p&gt;Ok, these two B Plans have stimulated my rambling. What if I incorporate the Chat GPT API to provide answers in natural language, using Orama for the time-stamped results? That way, I can have a contextual conversation with the generated excerpt from Chat GPT and rely on the accurate source of information and timestamp reference from Orama search results.&lt;/p&gt;

&lt;p&gt;Alright, alright, it's time to come back to reality now. &lt;a class="mentioned-user" href="https://dev.to/micheleriva"&gt;@micheleriva&lt;/a&gt;, I'm blaming you for this mind-bending journey 😂!&lt;/p&gt;

&lt;p&gt;Before wrapping up this article, I want to extend my heartfelt appreciation to Michele, Paolo, Angela, and everyone involved in the hard work on Orama. Hey folks, keep up the great work—I'm a big fan!&lt;/p&gt;

</description>
      <category>whisper</category>
      <category>orama</category>
      <category>astro</category>
    </item>
  </channel>
</rss>
