<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
   <channel>
      <title>Latest blog posts</title>
      <link>https://sojourn.ngonike.dev/blog/rss/</link>
      <description />
      <atom:link href="https://sojourn.ngonike.dev/blog/rss/" rel="self" />
      <language>en-us</language>
      <lastBuildDate>Thu, 30 Oct 2025 01:24:11 +0000</lastBuildDate>
      
      <item>
         <title>astro-php-ssr - Run PHP Routes Inside Astro</title>
         <link>https://sojourn.ngonike.dev/blog/astro-php-ssr-run-php-routes-in-astro</link>
         <media:content medium="image" url="https://cdn.buttercms.com/ZNdeIblHQ72gJpUylzB1"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Thu, 30 Oct 2025 01:24:11 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/astro-php-ssr-run-php-routes-in-astro</guid>
         <description>Bridging Two Worlds: Introducing astro-php-ssr - Run PHP Routes Inside Astro If you&#x27;ve ever found yourself caught between the modern, blazing-fast world of Astro and the need to integrate legacy PHP code or leverage PHP&#x27;s ecosystem, you&#x27;re not alone. Today, I&#x27;m excited to introduce astro-php-ssr - a seamless integration that ...</description>
         <content:encoded>
        <![CDATA[<h1>Bridging Two Worlds: Introducing astro-php-ssr - Run PHP Routes Inside Astro</h1>
<p>If you've ever found yourself caught between the modern, blazing-fast world of Astro and the need to integrate legacy PHP code or leverage PHP's ecosystem, you're not alone. Today, I'm excited to introduce <strong>astro-php-ssr</strong> - a seamless integration that lets you run PHP routes directly inside your Astro SSR applications.</p>
<h2>The Problem: Modern Frontend, Legacy Backend</h2>
<p>Astro has revolutionized how we build content-focused websites. Its island architecture, zero-JS-by-default philosophy, and incredible performance make it a developer favorite. But what happens when you need to:</p>
<ul>
<li>Integrate existing PHP APIs or services</li>
<li>Work with PHP-based CMSs or legacy systems</li>
<li>Leverage PHP libraries without rewriting everything in JavaScript</li>
<li>Gradually migrate a PHP application to a modern stack</li>
</ul>
<p>Until now, you'd be stuck managing separate servers, dealing with CORS issues, or embarking on costly rewrites.</p>
<h2>Enter astro-php-ssr</h2>
<p><strong>astro-php-ssr</strong> is a lightweight Astro integration that runs <code>.php</code> files directly inside your Astro SSR application using <code>php-cgi</code> or <code>php</code> as a fallback. No separate PHP server required. No complex proxy configurations. Just seamless PHP integration.</p>
<h3>Key Features</h3>
<p>✅ <strong>Seamless Integration</strong> - Works with <code>astro dev</code> and production SSR<br>✅ <strong>Full Request Support</strong> - Handles GET, POST, and other HTTP methods<br>✅ <strong>Flexible Configuration</strong> - Customize PHP binary path and PHP file directory<br>✅ <strong>Zero External Dependencies</strong> - Uses your existing PHP installation<br>✅ <strong>TypeScript Support</strong> - Full type definitions included</p>
<h2>Installation</h2>
<p>Getting started is incredibly simple:</p>
<pre><code>npm install astro-php-ssr
</code></pre>
<p>Or with your preferred package manager:</p>
<pre><code>yarn add astro-php-ssr
# or
pnpm add astro-php-ssr
</code></pre>
<p><strong>Prerequisites</strong>: You'll need <code>php-cgi</code> (preferred) or <code>php</code> installed on your system. Check with:</p>
<pre><code>php-cgi -v
# or
php -v
</code></pre>
<h2>Basic Usage</h2>
<h3>1. Configure Your Astro Project</h3>
<p>First, add the integration to your <code>astro.config.mjs</code>:</p>
<pre><code>import { defineConfig } from 'astro/config';
import node from '@astrojs/node';
import astroPhpSSR from 'astro-php-ssr';

export default defineConfig({
  output: 'server',
  adapter: node({ mode: 'standalone' }),
  integrations: [
    astroPhpSSR({
      phpDir: './php',        // Where your PHP files live
      phpBinary: 'php-cgi'    // Or 'php' as fallback
    })
  ]
});
</code></pre>
<h3>2. Create Your PHP Directory Structure</h3>
<pre><code>your-project/
├── php/
│   ├── api/
│   │   └── hello.php
│   └── contact.php
├── src/
│   └── pages/
│       └── index.astro
└── astro.config.mjs
</code></pre>
<h3>3. Write Your PHP Routes</h3>
<p>Create a simple API endpoint at <code>php/api/hello.php</code>:</p>
<pre><code>&lt;?php
header('Content-Type: application/json');

$name = $_GET['name'] ?? 'World';
echo json_encode([
    'message' =&gt; "Hello, $name!",
    'timestamp' =&gt; time()
]);
</code></pre>
<h3>4. Access Your PHP Routes</h3>
<p>Your PHP files are automatically served under <code>/php/</code>:</p>
<pre><code><a href="http://localhost:4321/php/api/hello.php?name=Astro">http://localhost:4321/php/api/hello.php?name=Astro</a>
</code></pre>
<p>Response:</p>
<pre><code>{
  "message": "Hello, Astro!",
  "timestamp": 1698624000
}
</code></pre>
<h2>Real-World Examples</h2>
<h3>Example 1: Contact Form Handler</h3>
<p>Create a contact form handler in <code>php/contact.php</code>:</p>
<pre><code>&lt;?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = $_POST['name'] ?? '';
    $email = $_POST['email'] ?? '';
    $message = $_POST['message'] ?? '';
    
    // Validate
    if (empty($name) || empty($email) || empty($message)) {
        http_response_code(400);
        echo json_encode(['error' =&gt; 'All fields are required']);
        exit;
    }
    
    // Process (send email, save to database, etc.)
    mail('admin@example.com', 'Contact Form', $message);
    
    echo json_encode(['success' =&gt; true]);
} else {
    http_response_code(405);
    echo json_encode(['error' =&gt; 'Method not allowed']);
}
</code></pre>
<p>Use it in your Astro component:</p>
<pre><code>---
// src/pages/contact.astro
---

&lt;form action="/php/contact.php" method="POST"&gt;
  &lt;input type="text" name="name" placeholder="Your Name" required /&gt;
  &lt;input type="email" name="email" placeholder="Your Email" required /&gt;
  &lt;textarea name="message" placeholder="Your Message" required&gt;&lt;/textarea&gt;
  &lt;button type="submit"&gt;Send&lt;/button&gt;
&lt;/form&gt;
</code></pre>
<h3>Example 2: WordPress REST API Bridge</h3>
<p>Integrate WordPress content without exposing your WordPress installation:</p>
<pre><code>&lt;?php
// php/api/posts.php
$wp_url = '<a href="https://your-wordpress-site.com">https://your-wordpress-site.com</a>';
$endpoint = '/wp-json/wp/v2/posts';

$response = file_get_contents($wp_url . $endpoint);
header('Content-Type: application/json');
echo $response;
</code></pre>
<p>Fetch in your Astro page:</p>
<pre><code>---
// src/pages/blog.astro
const response = await fetch('<a href="http://localhost:4321/php/api/posts.php')">http://localhost:4321/php/api/posts.php')</a>;
const posts = await response.json();
---

&lt;div&gt;
  {posts.map(post =&gt; (
    &lt;article&gt;
      &lt;h2&gt;{post.title.rendered}&lt;/h2&gt;
      &lt;div set:html={post.excerpt.rendered} /&gt;
    &lt;/article&gt;
  ))}
&lt;/div&gt;
</code></pre>
<h3>Example 3: Database Operations</h3>
<p>Access your MySQL database using PHP's native drivers:</p>
<pre><code>&lt;?php
// php/api/users.php
$db = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');

$stmt = $db-&gt;query('SELECT id, name, email FROM users LIMIT 10');
$users = $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);

header('Content-Type: application/json');
echo json_encode($users);
</code></pre>
<h2>Advanced Configuration</h2>
<h3>Custom PHP Binary Path</h3>
<p>If your PHP installation is in a non-standard location:</p>
<pre><code>astroPhpSSR({
  phpDir: './php',
  phpBinary: '/usr/local/bin/php-cgi'
})
</code></pre>
<h3>Multiple PHP Directories</h3>
<p>You can structure your PHP files however you like within the <code>phpDir</code>:</p>
<pre><code>php/
├── api/
│   ├── v1/
│   │   └── users.php
│   └── v2/
│       └── users.php
├── admin/
│   └── dashboard.php
└── public/
    └── info.php
</code></pre>
<p>Access them at:</p>
<ul>
<li><code>/php/api/v1/users.php</code></li>
<li><code>/php/api/v2/users.php</code></li>
<li><code>/php/admin/dashboard.php</code></li>
<li><code>/php/public/info.php</code></li>
</ul>
<h2>Performance Considerations</h2>
<p><strong>astro-php-ssr</strong> spawns a PHP process for each request using CGI. While this works great for:</p>
<ul>
<li>Low to moderate traffic sites</li>
<li>Development environments</li>
<li>Internal tools and dashboards</li>
<li>API endpoints that don't need millisecond response times</li>
</ul>
<p>For high-traffic production applications, consider:</p>
<ul>
<li>Caching PHP responses</li>
<li>Using PHP-FPM for long-running PHP processes</li>
<li>Rate limiting your PHP endpoints</li>
<li>Offloading heavy computation to background jobs</li>
</ul>
<h2>Use Cases</h2>
<p>This integration shines in several scenarios:</p>
<ol>
<li>
<p><strong>Legacy Integration</strong>: You have an existing PHP codebase and want to modernize the frontend without a complete rewrite</p>
</li>
<li>
<p><strong>Gradual Migration</strong>: You're moving from PHP to a modern stack and need both worlds to coexist</p>
</li>
<li>
<p><strong>PHP-Specific Libraries</strong>: You need functionality that's only available in PHP (certain payment gateways, legacy APIs, etc.)</p>
</li>
<li>
<p><strong>Content Management</strong>: Integrating with PHP-based CMSs like WordPress, Drupal, or custom systems</p>
</li>
<li>
<p><strong>Prototyping</strong>: Quickly spin up backend functionality using PHP's extensive ecosystem</p>
</li>
</ol>
<h2>Limitations &amp; Considerations</h2>
<ul>
<li><strong>Requires PHP</strong>: Your deployment environment must have <code>php-cgi</code> or <code>php</code> installed</li>
<li><strong>CGI Performance</strong>: Each request spawns a new PHP process (consider PHP-FPM for production)</li>
<li><strong>Session Management</strong>: PHP sessions work, but coordinate with Astro's session handling</li>
<li><strong>File Uploads</strong>: Supported through standard PHP <code>$_FILES</code> handling</li>
</ul>
<h2>Deployment</h2>
<h3>Deploying to Vercel/Netlify</h3>
<p>These platforms don't support PHP out of the box. Consider:</p>
<ul>
<li>Using Vercel/Netlify for static Astro content</li>
<li>Deploying PHP portions to a PHP-friendly platform</li>
<li>Using serverless PHP options</li>
</ul>
<h3>Deploying to VPS/Traditional Hosting</h3>
<p>This is where <strong>astro-php-ssr</strong> really shines:</p>
<ol>
<li>Ensure PHP is installed: <code>sudo apt install php-cgi</code></li>
<li>Build your Astro project: <code>npm run build</code></li>
<li>Run with Node: <code>node dist/server/entry.mjs</code></li>
</ol>
<p>Works perfectly on DigitalOcean, Linode, AWS EC2, or any VPS with Node.js and PHP.</p>
<h2>Roadmap</h2>
<p>Future enhancements I'm considering:</p>
<ul>
<li>PHP-FPM support for better performance</li>
<li>Built-in caching layer</li>
<li>Request/response logging</li>
<li>Hot reload for PHP files in development</li>
<li>More granular error handling</li>
</ul>
<h2>Try It Yourself</h2>
<p>Want to see it in action? Check out the live demo:</p>
<p><a href="https://replit.com/@yourusername/astro-php-ssr-demo"><img alt="Run on Replit" src="https://replit.com/badge"></a></p>
<p>Or install it in your project:</p>
<pre><code>npm install astro-php-ssr
</code></pre>
<h2>Conclusion</h2>
<p><strong>astro-php-ssr</strong> bridges the gap between Astro's modern, performant frontend architecture and PHP's mature, extensive ecosystem. Whether you're integrating legacy code, gradually migrating to a modern stack, or just need PHP's specific capabilities, this integration makes it seamless.</p>
<p>The web development landscape doesn't have to be all-or-nothing. Sometimes the best solution is bringing the best of both worlds together.</p>
<hr>
<h3>Links</h3>
<ul>
<li>📦 <a href="https://www.npmjs.com/package/astro-php-ssr">npm Package</a></li>
<li>💻 <a href="https://github.com/GabrielOnike/astro-php-ssr">GitHub Repository</a></li>
<li>🐛 <a href="https://github.com/GabrielOnike/astro-php-ssr/issues">Report Issues</a></li>
<li>🎯 <a href="https://replit.com/@yourusername/astro-php-ssr-demo">Live Demo</a></li>
</ul>
<hr>
<p><em>Have you used astro-php-ssr in your project? I'd love to hear about your experience! Drop a comment below or open an issue on GitHub.</em></p>]]>
      </content:encoded>
      </item>
      
      <item>
         <title>Overcoming LTR and RTL in React-Grid-Layout Library</title>
         <link>https://sojourn.ngonike.dev/blog/rtl-ltr-support-react-grid-layout</link>
         <media:content medium="image" url="https://cdn.buttercms.com/PR4Yoj0OTAWkx1hMsB9S"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Tue, 05 Nov 2024 06:10:00 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/rtl-ltr-support-react-grid-layout</guid>
         <description>Struggling with RTL support in React-Grid-Layout? Dive into our comprehensive guide on overcoming LTR and RTL limitations in this popular library. We cover practical solutions, including adjusting CSS transforms, using MutationObserver, and ultimately implementing a stable workaround by keeping the grid in LTR while applying RTL styling to widget contents. Perfect for developers seeking robust, user-friendly RTL support in dynamic dashboards ...</description>
         <content:encoded>
        <![CDATA[<p>In modern web development, creating applications that support both Left-to-Right (LTR) and Right-to-Left (RTL) languages is crucial for global accessibility. However, not all libraries provide seamless RTL support out of the box. We set out to create a highly dynamic dashboard with various draggable and resizable widgets, using the popular <strong>React-Grid-Layout</strong> library. This library allows us to arrange components within a responsive grid, where users can freely drag, resize, and rearrange widgets as they wish. <strong>React-Grid-Layout</strong> lacks built-in RTL support, which presents challenges for projects that need to accommodate RTL languages, such as Arabic or Hebrew. This blog post delves into the challenges I faced when working with the <code>react-grid-layout</code> library especially in RTL contexts and explores practical solutions to overcome them.</p>
<h2>Introduction to the Project</h2>
<p>We implemented theme switching to toggle direction switching to toggle between LTR and RTL layouts. While MUI provides straightforward RTL support for components, React-Grid-Layout&rsquo;s lack of native RTL compatibility became an issue, particularly as users switched between LTR and RTL. The key technologies and libraries used in our project include:</p>
<ul>
<li><strong>React</strong>: For building the user interface.</li>
<li><strong>Material-UI (MUI)</strong>: For pre-built components and styling.</li>
<li><strong>React-Grid-Layout</strong>: For creating a draggable and resizable grid layout.</li>
<li><strong>Redux</strong>: For state management.</li>
<li><strong>Lodash</strong>: For utility functions like throttling and debouncing.</li>
</ul>
<h2>The RTL Issue with React-Grid-Layout</h2>
<p>While <code>react-grid-layout</code> is a powerful library for creating responsive grid layouts with drag-and-drop capabilities, it lacks built-in support for RTL layouts. React-Grid-Layout uses absolute positioning and CSS transforms to position elements within the grid. For an LTR layout, these positions are calculated from the top-left corner of the grid, with elements positioned using positive <code>translate</code> values for X and Y coordinates. However, for RTL, the library does not invert the X-axis positions to start from the top-right, causing widgets to overflow out of view when switched to RTL mode&nbsp; especially on larger screens. This issue stems from the library's internal calculations, which assume an LTR context.<br><br></p>
<h3>Community Discussions and Attempts</h3>
<p>Many developers have faced similar challenges. On GitHub, issues like <a href="https://github.com/react-grid-layout/react-grid-layout/issues/682" target="_new" rel="noopener">Issue #682</a> and <a href="https://github.com/react-grid-layout/react-grid-layout/pull/875" target="_new" rel="noopener">Pull Request #875</a> highlight attempts to introduce RTL support. Some have proposed modifying the library's core code, while others suggest workarounds using CSS transformations.&nbsp;<br>Our attempt involved solving this issue without modifying the core code since our project needed to be sustainable.</p>
<h3>Example from the Community</h3>
<p>One user shared a solution that involved reversing the order of grid items based on the locale:</p>
<pre><code>const getLayout = (locale) =&gt; {
  let layout = [];
  if (locale !== 'ar') {
    // Standard LTR layout generation
  } else {
    // Reverse the grid items for RTL
  }
  return layout;
};
</code></pre>
<p>However, modifying the grid generation logic can be complex and doesn't address dynamic changes in direction and some solution even required using the <code>i8n library</code>.</p>
<h2>Initial Observations and Attempts</h2>
<p>Upon inspecting the DOM, I observed that each grid item has a&nbsp;<code>transform: translate(x, y)</code> style applied. While in RTL mode, the&nbsp;<code>x</code> value causes the widgets to overflow to the right. I observed via trial and error that by simply adding a negative sign to the&nbsp;<code>x</code> value, the widgets align correctly:</p>
<pre><code>/* Before: While in RTL direction*/
transform: translate(300px, 20px);

/* After adding negative sign in RTL  */
transform: translate(-300px, 20px);
</code></pre>
<h3>Implementing a Temporary Solution with <code>useEffect</code></h3>
<p>An initial attempt involved using a <code>useEffect</code> hook to programmatically adjust the <code>transform</code> styles of all the widgets by targeting the class whenever the direction changed:</p>
<pre><code>const isRTL = theme.direction === 'rtl'                                                        <br> <br>useEffect(() =&gt; {
  const adjustTransforms = () =&gt; {
    const gridItems = document.querySelectorAll('.react-grid-item');
    gridItems.forEach((item) =&gt; {
      const transform = item.style.transform;
      if (transform) {
        const [x, y] = transform.match(/-?\d+/g).map(Number);
        const adjustedX = isRTL ? -x : x;
        item.style.transform = `translate(${adjustedX}px, ${y}px)`;
      }
    });
  };

  adjustTransforms();
}, [isRTL]);
</code></pre>
<p>While this solution aligned widgets correctly in RTL mode initially, it had several limitations:</p>
<ul>
<li><strong>Temporary Adjustment</strong>: Each time the layout changed or the user toggled direction, the transform values would revert, causing widgets to jump back to their original positions.</li>
<li><strong>Non-Persistent Behavior</strong>: The <code>useEffect</code> only provided a temporary fix, and the layout would revert if users attempted to resize or drag elements.</li>
</ul>
<h2>Challenges with Dragging in RTL</h2>
<p>Even with the temporary fix in place, a bigger issue surfaced when trying to drag widgets in RTL mode. Modifying X-axis positions programmatically while dragging caused runtime errors:</p>
<pre><code>TypeError: Cannot assign to read-only property 'x' of object '#&lt;Object&gt;'
</code></pre>
<p>This error stemmed from attempting to modify immutable properties within the library's internal layout structure. React-Grid-Layout relies on specific drag-and-drop logic to calculate and update X and Y positions, and our solution of adding a negative X value clashed with the library&rsquo;s internal handling.<br><br></p>
<h2>Exploring Advanced Solutions</h2>
<p>To address the flickering and performance issues caused by the continuous adjustments, a <code>MutationObserver</code> was introduced to monitor changes and re-apply the transformations:</p>
<pre><code>useEffect(() =&gt; {
  let isAdjusting = false;

  const adjustTransforms = throttle(() =&gt; {
    if (isAdjusting) return;
    isAdjusting = true;
    // Adjust transforms
    isAdjusting = false;
  }, 100);

  const observer = new MutationObserver(() =&gt; {
    if (!isAdjusting) {
      adjustTransforms();
    }import { throttle } from 'lodash';

useEffect(() =&gt; {
    const adjustWidgetTransforms = throttle(() =&gt; {
        const gridItems = document.querySelectorAll('.react-grid-item');
        gridItems.forEach((item) =&gt; {
            const transform = item.style.transform;
            if (transform &amp;&amp; transform.startsWith('translate')) {
                const values = transform.match(/translate\(([^)]+)\)/)[1].split(', ');
                const x = parseFloat(values[0]);
                const y = parseFloat(values[1]);

                const adjustedX = isRTL ? -x : x;
                item.style.transform = `translate(${adjustedX}px, ${y}px)`;
            }
        });
    }, 100);

    const observer = new MutationObserver(adjustWidgetTransforms);
    observer.observe(document.querySelector('.react-grid-layout'), { attributes: true, subtree: true });
    
    return () =&gt; {
        observer.disconnect();
        adjustWidgetTransforms.cancel();
    };
}, [isRTL]);
&nbsp; });

  const config = { attributes: true, attributeFilter: ['style'], subtree: true };
  const gridItems = document.querySelectorAll('.react-grid-item');
  gridItems.forEach((item) =&gt; observer.observe(item, config));

  return () =&gt; observer.disconnect();
}, [isRTL]);
</code></pre>
<p>While this approach improved the fix slightly, it still faced limitations:</p>
<ul>
<li><strong>Performance Overhead</strong>: MutationObserver added a significant performance overhead by constantly monitoring layout changes, leading to lag and, in some cases, browser crashes.</li>
<li><strong>Inconsistent Behavior</strong>: Even with throttling, the widgets&rsquo; positions would still flicker between LTR and RTL positions, resulting in an unstable user experience.</li>
</ul>
<h2>The Final Approach: Keeping the Grid LTR</h2>
<p>Given the challenges with manipulating the grid's direction and the internal complexities of the library, and after several unsuccessful attempts, we decided on an alternative approach. A more sustainable solution was adopted: <strong>Keep the <code>react-grid-layout</code> container in LTR mode and adjust only the inner contents of the widgets to be RTL</strong>.</p>
<h3>Why This Approach Works</h3>
<p>Since users primarily interact with the inner content of widgets (e.g., text, icons), applying RTL styling to these contents achieves the desired look. Meanwhile, React-Grid-Layout remains in LTR, ensuring that positioning, dragging, and resizing behaviors are not disrupted. The Dashboard Layout and other wrap around components can have their directions switched and the internal components of the React Grid Layout can also have their internal components switched while leaving Just the ReactGridLayout alone to function as is.</p>
<p>In practice, this approach is effective because users can still rearrange widgets freely without worrying about grid alignment. The internal contents align properly, and the grid layout remains stable.</p>
<ul>
<li><strong>Simplicity</strong>: By not altering the grid's core behavior, we avoid conflicts with drag-and-drop functionality.</li>
<li><strong>Consistency</strong>: Widgets remain draggable and resizable as intended.</li>
<li><strong>Flexibility</strong>: Inner widget contents can be easily adjusted to match the desired text direction.</li>
</ul>
<h3>Implementing the Solution</h3>
<h4>Forcing LTR on the Grid Layout</h4>
<p>Wrap the <code>ResponsiveGridLayout</code> component and set its direction to LTR:</p>
<pre><code>&lt;div style={{ direction: 'ltr' }}&gt;
  &lt;ResponsiveGridLayout {...gridProps} style={{ direction: 'ltr'}} &gt;
    {/* Grid items */}
  &lt;/ResponsiveGridLayout&gt;
&lt;/div&gt;
</code></pre>
<h4>Adjusting Widget Contents</h4>
<p>For each widget, wrap its contents with a container that conditionally applies RTL styling based on the application's direction:</p>
<pre><code>const Widget = ({ isRTL, children }) =&gt; (
  &lt;div style={{ direction: isRTL ? 'rtl' : 'ltr' }}&gt;
    {children}
  &lt;/div&gt;
);
</code></pre>
<p>Use the <code>Widget</code> component in the grid items:</p>
<pre><code>&lt;ResponsiveGridLayout {...gridProps} style={{ direction: 'ltr'}}&gt;
  &lt;div key="widget1"&gt;
    &lt;Widget isRTL={isRTL}&gt;
      {/* Widget 1 contents */}
    &lt;/Widget&gt;
  &lt;/div&gt;
  &lt;div key="widget2"&gt;
    &lt;Widget isRTL={isRTL}&gt;
      {/* Widget 2 contents */}
    &lt;/Widget&gt;
  &lt;/div&gt;
  {/* Additional widgets */}
&lt;/ResponsiveGridLayout&gt;
</code></pre>
<h4>Example of a Widget Component</h4>
<p>Here's an example of a simple widget that adjusts its content direction:</p>
<pre><code>const TextWidget = ({ isRTL, text }) =&gt; (
  &lt;div style={{ direction: isRTL ? 'rtl' : 'ltr', padding: '10px' }}&gt;
    &lt;p&gt;{text}&lt;/p&gt;
  &lt;/div&gt;
);
</code></pre>
<p>Use it within the grid:</p>
<pre><code>&lt;div key="textWidget"&gt;
  &lt;TextWidget isRTL={isRTL} text="Hello, World!" /&gt;
&lt;/div&gt;
</code></pre>
<h3>Benefits of This Solution</h3>
<ul>
<li><strong>Drag Functionality Preserved</strong>: Since the grid remains in LTR, dragging and resizing work without additional adjustments.</li>
<li><strong>Content Alignment</strong>: Widget contents correctly align according to the text direction.</li>
<li><strong>Scalability</strong>: New widgets can be added without modifying the grid logic.</li>
</ul>
<h2>Conclusion</h2>
<p>Implementing RTL support in libraries that don't natively support it can be challenging. While initial attempts at manipulating the grid's transformations provided temporary fixes, they introduced new issues with interactivity and performance. By keeping the grid layout in LTR and adjusting only the inner components, we achieve a balance between functionality and user experience.</p>
<p>In this project, the lack of RTL support in React-Grid-Layout led us through several iterative solutions, from adding negative signs to transform values, to using <code>useEffect</code>, <code>MutationObserver</code>, and throttling. Ultimately, forcing React-Grid-Layout to stay in LTR mode while applying RTL styling only to widget contents provided a stable, user-friendly solution.</p>
<p>This approach is a robust and scalable solution for projects that require RTL support in React-Grid-Layout. It allows developers to meet the visual requirements of RTL languages while maintaining the library&rsquo;s inherent layout and drag functionality.&nbsp;This approach ensures that users can interact with the dashboard as intended, regardless of the text direction, and sets a foundation for supporting RTL languages in a scalable and maintainable way.</p>
<h2>References</h2>
<ul>
<li><a href="https://github.com/react-grid-layout/react-grid-layout/issues/682" target="_new" rel="noopener">React-Grid-Layout GitHub Issue #682</a></li>
<li><a href="https://github.com/react-grid-layout/react-grid-layout/pull/875" target="_new" rel="noopener">React-Grid-Layout Pull Request #875</a></li>
<li><a href="https://github.com/react-grid-layout/react-grid-layout/issues?q=rtl" target="_new" rel="noopener">React-Grid-Layout RTL Support Discussions</a></li>
<li><a href="https://github.com/react-grid-layout/react-grid-layout/issues/141" target="_new" rel="noopener">GitHub Issue #141</a></li>
<li><a href="https://www.npmjs.com/package/react-grid-layout" rel="follow noopener" target="_blank">React Grid Layout Library - NPM</a><br><a href="https://github.com/react-grid-layout/react-grid-layout/issues/453" rel="follow noopener" target="_blank">Github Issue #453</a><br><a href="https://github.com/react-grid-layout/react-resizable/pull/96" rel="follow">Github Issue #96</a></li>
</ul>
<p><br><br><br></p>]]>
      </content:encoded>
      </item>
      
      <item>
         <title>Building a Component Library | Storybook</title>
         <link>https://sojourn.ngonike.dev/blog/building-a-component-library-storybook</link>
         <media:content medium="image" url="https://cdn.buttercms.com/XLQKK4YATPaaeGWYZQcN"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Tue, 23 Apr 2024 11:26:00 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/building-a-component-library-storybook</guid>
         <description>Solving Storybook&#x27;s File Inclusion/Exclusion Challenge on the Sidebar Recently, I built a component library for the Terakota project. I made use of Storybook which stands out as a superb tool for effective documentation and component cataloging. Setting up the storybook for/in an existing project has been heavily treated here ...</description>
         <content:encoded>
        <![CDATA[<h3>Solving Storybook's File Inclusion/Exclusion Challenge on the Sidebar</h3>
<p>Recently, I built a component library for the Terakota project. I made use of Storybook which stands out as a superb tool for effective documentation and component cataloging. Setting up the storybook in/for an existing project has been heavily treated. I used a pseudo atomic structure in setting up the structure for the component stories architecture. I would focus on issues I faced for which solutions are not readily available on search engines. Storybook is storied for it's ability to handle MDX, JS and TS files as well as other file formats for the effective integration of component stories. However, integrating MDX files into Storybook isn't always straightforward. I'll share&nbsp; challenges I faced with including and excluding specific file types such as MDX in Storybook, the solutions I tried, the errors I encountered, and how I eventually resolved the issue.&nbsp;<br><br></p>
<ul>
<li><strong>Storybook Version: </strong>v7</li>
<li><strong>Node Versions:</strong> v18</li>
<li><strong>Associated Technologies:</strong> React | TypeScript&nbsp;</li>
</ul>
<h4>The Challenge</h4>
<p>The goal was simple: configure Storybook to include all MDX files in our project's sidebar, except those beginning with a certain phrase e.g.'codefile'. Subsequently we also discovered ways to exclude other file types or formats in the course of bringing about the solution. This requirement seemed straightforward but led to a significant hiccup in our configuration process.<br><br></p>
<h4>Initial Setup and Issue</h4>
<p>Here&rsquo;s the initial configuration setup in our <code>.storybook/main.(js/ts)</code> file:<br><br>```</p>
<div>
<div>import type { StorybookConfig } from "@storybook/react-webpack5";</div>
<br>
<div>const config: StorybookConfig = { <br>stories: [ <br>"../src/**/*.mdx",<br>"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)", <br>],</div>
<div>addons: [</div>
<div>"@storybook/preset-create-react-app",</div>
<div>"@storybook/addon-links",</div>
<div>...</div>
<div>"@storybook/theming",</div>
<div>],</div>
<div>framework: {</div>
<div>name: "@storybook/react-webpack5",</div>
<div>options: {},</div>
<div>},</div>
<div>docs: {</div>
<div>autodocs: "tag",</div>
<div>},</div>
<div>};</div>
<div>export default config;<br><br>```<br><br>Here&rsquo;s the initial configuration setup in our <code>.storybook/manager.(js/ts)</code> file:<br><br>```<br>
<div>
<div>import { addons } from '@storybook/addons';</div>
<div>import { create } from '@storybook/theming';</div>
<div>import logo from '../src/res/icons/terakota-logo-text.png';</div>
</div>
<br>
<div>
<div>const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;</div>
<br>
<div>addons.setConfig({</div>
<div>theme: create({</div>
<div>base: prefersDark ? 'dark' : 'light', // Or 'dark', depending on your preference</div>
<div>// Branding options</div>
<div>brandTitle: 'Sample',</div>
<div>brandUrl: '<a href="https://terakota.live">https://sample.live</a>',</div>
<div>brandImage: logo,&nbsp;</div>
<div>}),</div>
</div>
<br>```<br><br>However, this setup didn&rsquo;t work as expected. Including the line; &nbsp;&nbsp;<code>"../src/**/[!codefile]*.mdx"</code>, in the stories config of the manager.js file was supposed to exclude files like <code>codefile.mdx</code> but instead, it caused errors and didn't exclude the files correctly.<br><br>In the Sidebar image below, we have a Story folder; Data/Charts. The Charts stories has two files; Usage.mdx and Charts.ts. The content of the Usage.mdx file is imported into the Charts.ts file as a sub documentation and we would rather not have it appear in the sidebar. Here, we will apply the various code solutions and show you how you can keep the Usage file out of the sidebar OR keep the charts file out of the sidebar.<br><br><img src="https://cdn.buttercms.com/bVYagqqoSPvetQ5Z9ycA"><br>&nbsp;<br><br>
<h4>Troubleshooting and Debugging</h4>
<p>Upon encountering errors, we leveraged console logging to understand what files were being processed:<br><br>```</p>
<p>const glob = require('glob');<br>const path = require('path');</p>
<p>// Use an absolute path for clearer debugging&nbsp;<br>const projectRoot = path.resolve(__dirname, '../src');<br>const mdxFiles = glob.sync(`${projectRoot}/**/*.mdx`);</p>
<p>console.log("All MDX files found:", mdxFiles);</p>
<p>const filteredMdxFiles = mdxFiles.filter(file =&gt; {<br>&nbsp; const filename = path.basename(file);<br>&nbsp; const isExcluded = filename.startsWith('usage');<br>&nbsp; console.log("Testing file:", file, "Excluded:", isExcluded);<br>&nbsp; return !isExcluded;<br>});</p>
<p>console.log("Filtered MDX files:", filteredMdxFiles);</p>
<p>const config = {<br>&nbsp; stories: [<br>&nbsp; &nbsp; "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)",&nbsp;<br>&nbsp; &nbsp; ...filteredMdxFiles.map(file =&gt; path.relative(projectRoot, file)), // Convert back to relative paths<br>&nbsp; ],<br>};<br><br>```</p>
This helped us identify that the pattern used wasn&rsquo;t excluding files as intended. Instead, it seemed to misinterpret the exclusion pattern.<br><br>
<h4>Finding the Solutions</h4>
<p>Excluding MDX: <br>After several trials and understanding more about glob patterns and Storybook&rsquo;s interpretation of them, we refined our approach. We corrected the path handling by ensuring that paths were transformed relative to the correct base directory:<br><br>```</p>
<div>
<div>main.ts<br><br>import type { StorybookConfig } from "@storybook/react-webpack5";</div>
<br>
<div>const glob = require('glob');</div>
<div>const path = require('path');</div>
<br>
<div>const projectRoot = path.resolve(__dirname, '../src'); // Adjust as necessary to point to your project root</div>
<div>const storiesRoot = path.relative(projectRoot, path.resolve(__dirname, '../src/stories'));</div>
<div>const mdxFiles = glob.sync(`${projectRoot}/**/*.mdx`);</div>
<div>const filteredMdxFiles = mdxFiles.filter(file =&gt; !path.basename(file).startsWith('usage'))</div>
<div>.map(file =&gt; path.relative(storiesRoot, file)); // Convert to relative paths from the stories directory</div>
<br>
<div>const config: StorybookConfig = {</div>
<div>stories: [</div>
<div>"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)",</div>
<div>...filteredMdxFiles,</div>
<div>],</div>
<div>addons: [<br>...</div>
</div>
<p><br>```<br><br>This adjustment ensured that only the intended MDX files were included, and those starting with 'usage' were successfully excluded. This solution also works across most recent versions&nbsp;<br>of Storybook including version 6.</p>
<br>Excluding .js or other stories: this aspect involved changes to the manager.js file as well as changes to the stories file, in this case; charts.stories.ts.<br>We included a filer which is seemingly only available in Storybook &gt;=v7, and this filter allows you to add a tag using Storybook's addOn features. When this tag is added to the story,<br>the story will be automatically excluded from the sidebar. The word tag used for this example is 'pattern'<br><br>```<br>manager.js<br><br>...<br>
<div>
<div>brandImage: logo,&nbsp;</div>
<div>}),</div>
<div>sidebar: {</div>
<div>filters: {</div>
<div>patterns: (item) =&gt; {</div>
<div>return !item.tags.includes('pattern');</div>
<div>},</div>
<div>},</div>
<div>},</div>
<div>});</div>
</div>
<br>```<br><br>in the charts.stories.ts file, we add the tag like so<br><br>```<br>
<div>
<div>import React from 'react';</div>
<div>import type { Meta, StoryObj } from '@storybook/react';</div>
<div>import AgeDemographyChart from '../../../components/stats/charts/ageDemography';</div>
<div>import Usage from './usage.mdx';</div>
<br>
<div>const meta: Meta = {</div>
<div>title: 'Data/Charts/Charts',</div>
<div>component: AgeDemographyChart, // Specify a default component for the stories file</div>
<div>parameters: {</div>
<div>layout: 'centered',</div>
<div>githubUsername: 'GabrielOnike',</div>
<div>},</div>
<div>tags: ['pattern'],</div>
<div>// tags: ['autodocs'],</div>
<div>} satisfies Meta&lt;typeof AgeDemographyChart&gt;;</div>
<br>
<div>export default meta;</div>
</div>
</div>
<div>...<br><br>```<br><br>with the tag added, the chats story will now be excluded from the Sidebar.<br><br><br>The below image show the Sidebar without Usage.mdx file post implementation.<br><br><img src="https://cdn.buttercms.com/nNH9nOW6ST61PayM7Wep"></div>
<div><br>
<h4>Errors and Pitfalls to Avoid</h4>
<p>Throughout this process, several key learnings emerged:</p>
<ul style="list-style-type: disc;">
<li><strong>Verify Path Relativity</strong>: Always check that paths are correctly relative to where the Storybook configuration expects them to be.</li>
<li><strong>Glob Pattern Accuracy</strong>: Be meticulous with glob patterns, especially when trying to exclude specific files or patterns.</li>
<li><strong>Compatibility Checks</strong>: Keep an eye on dependency versions, especially with major tools like Storybook, to avoid compatibility issues.</li>
</ul>
<h4>Conclusion</h4>
<p>The journey to correctly configure Storybook to handle specific MDX files taught us the importance of understanding tooling deeply, particularly in how paths and glob patterns are handled. This experience not only refined our setup but also deepened our understanding of how Storybook integrates with our development environment, leading to more robust and maintainable configurations.</p>
<p>By sharing this story, I hope to assist others facing similar challenges, making their path smoother and their development process more efficient.</p>
<br>You may visit terakota.live and checkout the Storybook to view this implementation.</div>
</div>]]>
      </content:encoded>
      </item>
      
      <item>
         <title>AWS + Ruby on Rails</title>
         <link>https://sojourn.ngonike.dev/blog/aws-and-ruby-on-rails</link>
         <media:content medium="image" url="https://cdn.buttercms.com/XeELhrq9SFCq6I2VTqNU"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Tue, 26 Mar 2024 16:42:00 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/aws-and-ruby-on-rails</guid>
         <description>Successfully deploying a Ruby On Rails App for AWS Platform: 64bit Amazon Linux 2/3.6.17 Rails - v6.0+ Ruby - v3.0.4 - v3.2.2 Over the course of time, I have moved several of my applications to the Cloud. One of which is this my blog(Sojourn). While the applications for Cloud technology ...</description>
         <content:encoded>
        <![CDATA[<h4 style="text-align: left;"><span style="color: rgb(0, 0, 0);"><strong>DEPLOYING A RUBY ON RAILS APP FOR AWS&nbsp;</strong></span><br><br></h4>
<ul style="list-style-type: disc;">
<li><strong>AWS Service:</strong> Elastic Beanstalk</li>
<li><strong>AWS Platform:</strong> 64bit Amazon Linux 2/3.6.17</li>
<li><strong>Rails Versions:</strong> v6.0+ to v7.0+</li>
<li><strong>Ruby Versions:</strong> v3.0.4 to v3.2.2</li>
</ul>
<h4 style="text-align: left;">Over the course of time, I have moved several of my applications to the Cloud. One of which is this my blog(Sojourn). While the applications for Cloud technology are vast, this writeup focuses on deployment of a Web Application for the cloud using AWS.&nbsp; I will be narrating my experience in this process from my perspective deploying Rails applications as a Cloud DevOps Engineer specialising in AWS.<br>The goal? To deploy a Rails application seamlessly onto AWS Elastic Beanstalk using the AWS console, ensuring a smooth transition from development to production without sacrificing performance or stability.<br><br><br>CONTENTS</h4>
<h4 style="text-align: left;"><strong>Introduction - </strong>Why AWS?</h4>
<ul style="list-style-type: disc;">
<li>Overview of AWS, Ruby on Rails, AWS Elastic Beanstalk, Puma, and Nginx</li>
</ul>
<h4 style="text-align: left;"><strong>Setup and Deployment with AWS</strong></h4>
<ul style="list-style-type: disc;">
<li>Initial deployment to AWS Elastic Beanstalk</li>
<li>Setting up a Ruby on Rails application for deployment&nbsp;</li>
<li>Viewing errors with LogFiles</li>
</ul>
<h4 style="text-align: left;"><strong>Encountered Problems and Solutions</strong></h4>
<ul style="list-style-type: disc;">
<li>Problem 1: Deployment Failures due to Gemfile Issues</li>
<li>Solution 1: Cleaning and Specifying Gem Versions</li>
<li>Problem 2: <code>assets:precompile</code> Task Failures</li>
<li>Solution 2: Environment Configuration and Precompilation<br><br></li>
<li>Problem: Puma Configuration for AWS</li>
<li>Solution: Conditional Configuration for Development and Production</li>
<li>Problem: Nginx Reverse Proxy Configuration</li>
<li>Solution: Setting Up Unix Sockets and Permissions</li>
</ul>
<h4 style="text-align: left;"><strong>Using Github and&nbsp;AWS CodePipeline(CI/CD)</strong></h4>
<h4 style="text-align: left;"><strong>Common Pitfalls and How to Avoid Them</strong></h4>
<ul style="list-style-type: disc;">
<li>Understanding AWS Environment Constraints</li>
<li>Properly Managing Gemfile Dependencies</li>
<li>Configuring Web Servers for Different Environments</li>
</ul>
<h4 style="text-align: left;"><strong>Conclusion</strong></h4>
<ul style="list-style-type: disc;">
<li>Summary of Key Takeaways</li>
<li>Final Thoughts on Rails Deployment to AWS</li>
<li>Relevant Resources&nbsp;</li>
</ul>
<h4 style="text-align: left;"></h4>
<h3>1. Introduction</h3>
<p>Deploying a Ruby on Rails application involves several key components, each with its own set of configurations and challenges. AWS, with its robust ecosystem, promises scalability, reliability, and a suite of services that cater to various deployment needs. For Rails applications, AWS Elastic Beanstalk and its integration with the Puma web server and Nginx reverse proxy form a powerful triad that can handle the demands of modern web applications. While it is possible to deploy such an application via the command line using SSH, we embark on this deployment using the AWS console which is less complex and more suitable for our needs here. Before deploying this particular Rails 6 application on Amazon Linux 2(AL2), I had unsuccessfully attempted to deploy the same on Amazon Linux 2023(AL3) but after several attempts over the span of weeks, I fell back to the deprecated AL2 which i was much more familiar with before finding success. However, I will still need to deploy on AL3 but that upgrade has been tied to the Applications' upgrade to Rails 7 in the future since the AL2 will be phased out in 2025. I will reserve that process for the Part 2 of this writeup. Note that my attempts at AL3 necessitated the dockerization of the app as well as the use of AL3 specific Gemfiles and setup which still very much linger in this deployment, this writeup and subsequent follow up updates.</p>
<h3>2. Initial Setup and Deployment</h3>
<p>The deployment process begins with setting up the Rails application for deployment, including configuring the <code>Gemfile</code> and ensuring the application is ready for the AWS Elastic Beanstalk environment. Make sure your project starts and runs successfully on your local/development server before proceeding with your production deployment. Below is a sample Gemfile which achieved deployment success for your pleasure.<br><br>```<br><code>source '<a href="https://rubygems.org">https://rubygems.org</a>'</code><br><code>git_source(:github) { |repo| "<a href="https://github.com/#{repo}.git">https://github.com/#{repo}.git</a>" }</code></p>
<div>
<div><code>ruby '&gt;= 3.0.4', '&lt;= 3.2.2'</code><br><br></div>
<div><code>gem 'rails', '~&gt; 6.0.3', '&gt;= 6.0.3.6'</code></div>
<br>
<div><code>gem 'buttercms-rails', '~&gt;1.2.3'</code></div>
<br>
<div><code># Use sqlite3 is only used for development not for production</code></div>
<div><code>gem 'sqlite3', group: :development</code></div>
<br>
<div><code># Postgres(pg) is used for Production; for it to run locally you need the pg client installed on your desktop</code></div>
<code>gem 'pg'</code><br><br><code># nio4r gave errors until its version was specified here</code><br>
<div><code>gem 'nio4r', '= 2.7.1', group: :production</code></div>
<br><br>
<div><code>gem 'activerecord'</code></div>
<br>
<div><code>gem 'rake'</code><br><br></div>
<div><code># Specific use of Puma to get the app to work in production and development</code></div>
<div><code>gem 'puma'</code><br><br></div>
<div><code># Use SCSS for stylesheets</code></div>
<div><code>gem 'sassc-rails', '&gt;= 2.1.0'</code><br><br></div>
<div><code># Transpile app-like JavaScript. Read more: <a href="https://github.com/rails/webpacker">https://github.com/rails/webpacker</a></code></div>
<div><code>gem 'webpacker', '~&gt; 4.0'</code><br><br></div>
<div><code># Ruby 3.2.2 bundle update required this Pysch gem to overcome deployment errors on AWS</code></div>
<div><code>gem 'psych', '&lt; 4'</code><br><br></div>
<div><code># Turbolinks makes navigating your web application faster. Read more: <a href="https://github.com/turbolinks/turbolinks">https://github.com/turbolinks/turbolinks</a></code></div>
<div><code>gem 'turbolinks', '~&gt; 5'</code><br><br></div>
<div><code># Build JSON APIs with ease. Read more: <a href="https://github.com/rails/jbuilder">https://github.com/rails/jbuilder</a></code></div>
<div><code>gem 'jbuilder', '~&gt; 2.7'</code></div>
<br>
<div><code>#Bootstrap JavaScript depends on jQuery. If you're using Rails 5.1+, add the jquery-rails gem to your Gemfile</code></div>
<div><code>gem 'jquery-rails'</code></div>
<br>
<div><code># Reduces boot times through caching; required in config/boot.rb</code></div>
<div><code>gem 'bootsnap', '&gt;= 1.4.2', require: false</code></div>
<br>
<div><code># Gem to help manage meta tags</code></div>
<div><code>gem 'meta-tags'</code></div>
<br>
<div><code>group :development, :test do</code></div>
<div><code># Call 'byebug' anywhere in the code to stop execution and get a debugger console</code></div>
<div><code>gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]</code></div>
<div><code>end</code></div>
<br>
<div><code>group :development do</code></div>
<div><code># Access an interactive console on exception pages or by calling 'console' anywhere in the code.</code></div>
<div><code>gem 'web-console', '&gt;= 3.3.0'</code></div>
<div><code>gem 'listen', '~&gt; 3.2'</code><br><br></div>
<div><code># Spring speeds up development by keeping your application running in the background</code></div>
<div><code>gem 'spring'</code></div>
<div><code>gem 'spring-watcher-listen', '~&gt; 2.0.0'</code></div>
<div><code>end</code></div>
<br>
<div><code>group :test do</code></div>
<div><code># Adds support for Capybara system testing and selenium driver</code></div>
<div><code>gem 'capybara', '&gt;= 2.15'</code></div>
<div><code>gem 'selenium-webdriver'</code></div>
<div><code># Easy installation and use of web drivers to run system tests with browsers</code></div>
<div><code>gem 'webdrivers'</code></div>
<div><code>end</code></div>
<br>
<div><code># Windows and AL platform does not include zone Info files, so bundle the tzinfo-data gem</code></div>
<div><code>gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]</code><br>```<br><br>
<p><strong>Viewing errors with LogFiles<br></strong><br>The most effective way to debug AWS deployments is via the logfiles. These log files can be found in your environment(see Image below). While you can view the last 100 lines of the logfiles in the browser, AWS still requires you to download your log file bundles to enable full view of your log files. I found myself doing alot of log bundle downloads since the last 100 lines is sometimes insufficient to identify an error. One would hope that a future AWS console UI&nbsp;will enable a user to view updated full log files in the browser without having to exit the browser environment.<br>Some popular log files i had to regularly view in order of frequency include;&nbsp;<br>- <code>eb-engine.log</code> (for general deployment errors),&nbsp;<br>- <code>cfn-init.log</code>(for prebuild errors associated with your eb-extensions),&nbsp;<br>- <code>puma/puma.log</code>(for puma errors to confirm if server is responsive) and <br>- <code>nginx/nginx.log</code>(for nginx error lookup)&nbsp;<strong><br><br><img src="https://cdn.buttercms.com/edHUMkIrSEur23qz7ax1"></strong></p>
<img src="https://cdn.buttercms.com/c9bb8TZQtmDszpdQ0snP"></div>
</div>
<h3>3. Encountered Problems and Solutions</h3>
<h4>Problem 1: Deployment Failures due to Gemfile Issues</h4>
<p><strong>Solution 1</strong>: It's crucial to ensure that the <code>Gemfile</code> is clean and all dependencies are specified with compatible versions to prevent deployment failures. Some of the Gems required for Rails&nbsp;</p>
<h4>Problem 2: <code>assets:precompile</code> Task Failures</h4>
<p><strong>Solution 2</strong>: Configure the environment properly and ensure all assets are precompiled before deployment. This may involve running precompilation locally or configuring it to run on the server during deployment.<br><br></p>
<h3>4. Configuring Puma and Nginx</h3>
<p>Configuring Puma and Nginx correctly is crucial for the successful deployment of a Rails application on AWS.</p>
<p><strong>Problem: Puma Configuration for AWS</strong><br>During the deployment process on AWS, a significant hurdle encountered was the configuration of the Puma server in a production environment. The challenge arose when attempting to bind Puma to a Unix socket at <code>/var/run/puma/my_app.sock</code> for communication with Nginx, the reverse proxy server. This setup is typical for production environments to enhance performance and security. However, it led to errors when running the Rails server locally and on AWS. <br><strong>Example Error</strong>:<br>On AWS, the configuration did not manifest as an error message directly but resulted in a <code>504 Gateway Timeout</code> error, indicating a failure in communication between Nginx and Puma.<br>Locally the error manifested as: <br><code>Exiting ...rvm/gems/ruby-3.2.2/gems/puma-4.3.12/lib/puma/binder.rb:327:in `initialize': No such file or directory - connect(2) for /var/run/puma/my_app.sock (Errno::ENOENT)</code></p>
<p><strong>Solutions</strong>: Use conditional configuration in <code>config/puma.rb</code> to differentiate between development and production environments, especially for Unix socket bindings. The below can be added to your <code>config/puma.rb</code> file<br><br><code>rails_env = ENV.fetch("RAILS_ENV") { "development" }</code><br><code>if rails_env == "production"</code><br><code>&nbsp; bind "unix:///var/run/puma/my_app.sock"</code><br><code>&nbsp; pidfile "/var/run/puma/my_app.sock"</code><br><code>else</code><br><code>&nbsp; port ENV.fetch("PORT") { 3000 }</code><br><code>end</code><br><br><strong>Creating a Procfile</strong><br>There was also a need to create a Procfile at the root of the project to enforce a Puma config creation since AWS sometimes hindered this. In the Procfile we placed the following code to create the Puma config and execute it:<br><code>web: bundle exec puma -C /opt/elasticbeanstalk/config/private/pumaconf.rb</code>&nbsp;</p>
<p><strong>Problem: Nginx Reverse Proxy Configuration</strong><br>The configuration of Nginx as a reverse proxy to forward requests to the Puma server via the Unix socket posed another challenge. The <code>504 Gateway Timeout</code> error in production was a symptom of misconfiguration or the absence of the Unix socket Puma was supposed to bind to.</p>
<p><strong>Solution</strong>: The solution involved ensuring that Nginx was correctly configured to proxy requests to the Unix socket at <code>/var/run/puma/my_app.sock</code>. This required verifying the Nginx configuration files and ensuring they pointed to the correct socket path. Moreover, the <code>.ebextensions</code> script mentioned earlier played a crucial role in creating the necessary directory structure and permissions for the socket file, allowing both Puma and Nginx to communicate effectively.<br><br></p>
<p style="text-align: left;"><span style="font-weight: 600; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;">Using Github and AWS CodePipeline(CI/CD)<br></span><br>Continuous Integration and Continuous Deployment (CI/CD) allow for the automation, testing and deployment of applications in a fluid manner. AWS CodePipeline, in conjunction with GitHub, provides a powerful platform for implementing CI/CD for Ruby on Rails applications. Every time there is a code change AWS CodePipeline automates the build, test, and deployment phases of your application.&nbsp;This section assumes you have a Ruby on Rails application hosted on GitHub and aims to deploy it using AWS Elastic Beanstalk. The stages involve;<br><br>- <strong>Create a New Pipeline<br><img src="https://cdn.buttercms.com/804Y8LVOTVaAb5h4X7dT"></strong><br>- <strong>Source Stage : Here we use Github version 2, connect to our Github account and add the desired Repo and Branch&nbsp;<br><img src="https://cdn.buttercms.com/ni7h6rLpQYmMnbSLFzFM"><br>- Build Stage<br>We Skip the build stage here since our build process is described in our project files<br><br>- Deploy Stage: Our deployment provider is Elastic Beanstalk, we select the region of our project and select the application and environment name<br><img src="https://cdn.buttercms.com/tyA2wo0QfKvVXQZryeMh"><br><br>- Review and Create</strong></p>
<p>We review all the details provided and proceed to Create the pipeline<br><br>Finally our app begins the process of deployment and a successful deployment looks like the image below<br><img src="https://cdn.buttercms.com/6JaP0uSq217LDZySO62Q"></p>
<h3 style="text-align: left;">&nbsp;<br><br></h3>
<h3>5. Common Pitfalls/Errors and How to Avoid Them</h3>
<ul style="list-style-type: disc;">
<li><strong>Understanding AWS Environment Constraints</strong>: Be aware of the AWS environment's limitations and configurations, such as directory paths and user permissions.</li>
<li><strong>Properly Managing Gemfile Dependencies</strong>: Keep the <code>Gemfile</code> clean and ensure all dependencies are compatible.</li>
<li><strong>Configuring Web Servers for Different Environments</strong>: Use conditional logic in server configuration files to adapt to different environments seamlessly.<br><br></li>
</ul>
<h3>6. Conclusion</h3>
<p>Deploying a Ruby on Rails application to AWS Elastic Beanstalk with Puma and Nginx involves understanding and navigating through a series of challenges. By addressing these challenges with the solutions provided, developers can ensure a smoother deployment process and a more robust application environment. This journey underscores the importance of meticulous configuration and an in-depth understanding of both the application's and environment's requirements.</p>
<h3><br>Summary of Key Takeaways</h3>
<p>Deploying a Ruby on Rails application to AWS Elastic Beanstalk involves several critical steps and considerations that can significantly impact the success and reliability of your application in a production environment. Here are the key takeaways from our discussion:</p>
<ul>
<li>
<p><strong>Proper Gemfile Management</strong>: Ensuring your <code>Gemfile</code> is correctly managed by specifying gem versions and resolving dependencies is crucial to prevent deployment failures.</p>
</li>
<li>
<p><strong>Effective Use of Environment Variables</strong>: Leveraging environment variables for configuration settings enables smoother transitions between different environments (development, test, production) and enhances security.</p>
</li>
<li>
<p><strong>Asset Precompilation</strong>: Understanding and implementing the asset precompilation process is essential for Rails applications to ensure assets are served correctly in production.</p>
</li>
<li>
<p><strong>Database Migration</strong>: Automating database migrations as part of the deployment process ensures your database schema is always in sync with your application's expectations.</p>
</li>
<li>
<p><strong>Conditional Puma Configuration</strong>: Setting up Puma with conditional configuration for development and production environments allows for flexibility and prevents deployment issues related to web server configurations.</p>
</li>
<li>
<p><strong>Integrating CI/CD with GitHub and AWS CodePipeline</strong>: Automating the build, test, and deploy phases through CI/CD pipelines not only saves time but also reduces the risk of human error, ensuring a more reliable deployment process.</p>
</li>
</ul>
<p style="text-align: left;"><strong><br><br>RELEVANT RESOURCES</strong><br>Some of the relevant resources i used to overcome some pitfalls and errors are listed here below for your use. For further exploration in overcoming potential issues and to deepen your understanding of deploying Ruby on Rails applications to AWS, the following resources can be invaluable:<br><br>- <a href="https://stackoverflow.com/questions/40938155/right-way-to-deploy-rails-puma-postgres-app-to-elastic-beanstalk">https://www.stackoverflow.com/questions/40938155/right-way-to-deploy-rails-puma-postgres-app-to-elastic-beanstalk&nbsp;</a><br>- <a href="https://stackoverflow.com/questions/39525129/installing-gems-fails-in-deployment-aws-elastic-beanstalk">https://stackoverflow.com/questions/39525129/installing-gems-fails-in-deployment-aws-elastic-beanstalk</a><br>- <a href="https://stackoverflow.com/questions/73012901/deploying-rails-7-app-on-elastic-beanstalks-fails-with-nokogiri-error">https://stackoverflow.com/questions/73012901/deploying-rails-7-app-on-elastic-beanstalks-fails-with-nokogiri-error</a><br>- <a href="https://stackoverflow.com/questions/72307187/how-to-install-postgresql-client-to-amazon-ec2-linux-machine">https://stackoverflow.com/questions/72307187/how-to-install-postgresql-client-to-amazon-ec2-linux-machine</a><br>- <a href="https://stackoverflow.com/questions/65544527/aws-elastic-beanstalk-ruby-on-rails-6-app-deployment-error-with-nginx">https://stackoverflow.com/questions/65544527/aws-elastic-beanstalk-ruby-on-rails-6-app-deployment-error-with-nginx</a><br>- <a href="https://stackoverflow.com/questions/30355569/rails-application-deployed-on-elastic-beanstalk-with-puma-fails-502-errors-on/69092359#69092359">https://stackoverflow.com/questions/30355569/rails-application-deployed-on-elastic-beanstalk-with-puma-fails-502-errors-on/69092359#69092359</a><br>- <a href="https://stackoverflow.com/questions/66400979/why-am-i-getting-502-bad-gateway-nginx-1-18-0-rails-app-on-elastic-beanstalk">https://stackoverflow.com/questions/66400979/why-am-i-getting-502-bad-gateway-nginx-1-18-0-rails-app-on-elastic-beanstalk</a><br>- <a href="https://medium.com/swlh/what-should-you-know-about-deploying-a-rails-app-on-aws-elastic-beanstalk-fa47b9d834ed">https://medium.com/swlh/what-should-you-know-about-deploying-a-rails-app-on-aws-elastic-beanstalk-fa47b9d834ed</a><br>- <a href="https://medium.com/@williamjoshualacey/deploy-rails-app-to-aws-2854b2338708">https://medium.com/@williamjoshualacey/deploy-rails-app-to-aws-2854b2338708</a><br>- <a href="https://medium.com/@rachelchervin/aws-elastic-beanstalk-gotchas-with-rails-d23ac21487f7">https://medium.com/@rachelchervin/aws-elastic-beanstalk-gotchas-with-rails-d23ac21487f7</a><br>-&nbsp;<a href="https://www.codewithjason.com/deploy-ruby-rails-application-aws-elastic-beanstalk/">https://www.codewithjason.com/deploy-ruby-rails-application-aws-elastic-beanstalk/</a><br>- <a href="https://bentranz.medium.com/deploy-ruby-on-rails-application-to-aws-elastic-beanstalk-amazon-linux-2-138654b1ce41">https://bentranz.medium.com/deploy-ruby-on-rails-application-to-aws-elastic-beanstalk-amazon-linux-2-138654b1ce41</a><br>- <a href="https://bentranz.medium.com/setup-continuous-deployment-pipeline-for-aws-elastic-beanstalk-5f8edb38d872">https://bentranz.medium.com/setup-continuous-deployment-pipeline-for-aws-elastic-beanstalk-5f8edb38d872</a><br>- <a href="https://www.honeybadger.io/blog/rails-6-aws-elastic-beanstalk/">https://www.honeybadger.io/blog/rails-6-aws-elastic-beanstalk/</a><br>- <a href="https://repost.aws/questions/QUvEtL971cSsK0x0De-OTljw/how-can-i-deploy-a-rails-app-slite3-to-aws">https://repost.aws/questions/QUvEtL971cSsK0x0De-OTljw/how-can-i-deploy-a-rails-app-slite3-to-aws</a><br>- <a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/ruby-rails-tutorial.html">https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/ruby-rails-tutorial.html</a><br>- <a href="https://dev.to/forksofpower/make-the-move-from-sqlite3-to-postgres-in-rails-6-34m2">https://dev.to/forksofpower/make-the-move-from-sqlite3-to-postgres-in-rails-6-34m2</a><br>- <a href="https://copyprogramming.com/howto/deploy-rails-app-from-github-to-aws-elastic-beanstalk">https://copyprogramming.com/howto/deploy-rails-app-from-github-to-aws-elastic-beanstalk</a><br>- <a href="https://dev.to/sname/deploy-rails-app-from-github-to-aws-4kk0">https://dev.to/sname/deploy-rails-app-from-github-to-aws-4kk0</a><br>- <a href="https://semaphoreci.com/community/tutorials/how-to-deploy-a-ruby-on-rails-application-to-elastic-beanstalk-with-semaphore">https://semaphoreci.com/community/tutorials/how-to-deploy-a-ruby-on-rails-application-to-elastic-beanstalk-with-semaphore</a><br>- <a href="https://benreynolds4.medium.com/gateway-timeout-deploying-rails-application-to-elastic-beanstalk-88bc8a0c9833">https://benreynolds4.medium.com/gateway-timeout-deploying-rails-application-to-elastic-beanstalk-88bc8a0c9833</a><br>- <a href="https://www.zshawnsyed.com/2020/06/10/deploying-to-aws/">https://www.zshawnsyed.com/2020/06/10/deploying-to-aws/</a><br>- <a href="https://www.zshawnsyed.com/2020/06/02/setting-up-aws/">https://www.zshawnsyed.com/2020/06/02/setting-up-aws/</a><br>- <a href="https://www.freecodecamp.org/news/how-to-deploy-a-rails-5-2-postgresql-app-on-aws-elastic-beanstalk-34e5cec3a984/">https://www.freecodecamp.org/news/how-to-deploy-a-rails-5-2-postgresql-app-on-aws-elastic-beanstalk-34e5cec3a984/</a></p>
<h4 style="text-align: left;"></h4>
<h4 style="text-align: left;"><br><br></h4>
<h4 style="text-align: left;"><br><br><br></h4>]]>
      </content:encoded>
      </item>
      
      <item>
         <title>Tomato Farming in Northern Nigeria: An Exposé</title>
         <link>https://sojourn.ngonike.dev/blog/tomato-farming-in-northern-nigeria-an-expose</link>
         <media:content medium="image" url="https://cdn.buttercms.com/MNKD78gnSMOtXY6K6ltO"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Mon, 06 Dec 2021 01:57:00 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/tomato-farming-in-northern-nigeria-an-expose</guid>
         <description>This piece exposes my foray into farming, my passion for development and the way technology affects farming today. I also discuss the depth of technological penetration in local farming communities within the scope of this piece</description>
         <content:encoded>
        <![CDATA[<p>Wondering what this Techie has to do with farming ?</p>
<p>Well turns out, a lot !</p>
<p>This piece exposes my infrequent foray into farming, my love for growth and development and the way technology affects farming in this time. I also discuss the depth of technological penetration in local farming communities within the scope of this article. I journal the role non-governmental organisations(NGOs) play in the local scene, opportunities abound in the sector, the art of community engagement, penetration and negotiation in a subtle approach.</p>
<p>In short, this piece is about an adventure. 3, 2, 1 ...</p>
<p>Let's dive.</p>
<p></p>
<p><strong>CONTENT</strong></p>
<ul>
<li><strong>Introduction</strong></li>
<li><strong>The Journey</strong></li>
<li><strong>Engagement</strong></li>
<li><strong>Farming and Technology</strong></li>
<li><strong>Issues, Solutions and My Proposal</strong></li>
<li><strong>Business and Value Chain Prospects&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</strong></li>
<li><strong>Conclusion</strong></li>
</ul>
<p><strong></strong></p>
<p><strong>INTRODUCTION</strong></p>
<p>My initial incursion in commercial farming as an adult was in the last quarter of 2016, working for a start up in a digital and business support role. My stint there was short but my exposure was wide. It was at this company I first built a business website. At the time, the company ran a budding export company alongside the consulting side of the business. The prior experience of our lead in the field of agri-business influenced our attempt at the agri-export chain. I was a part of this movement. We were trying to export a cash crop with targeted foreign demand at the time. We quickly made connections to export markets. I brought to bear all i knew about farming and started to learn all that was relevant to this agribusiness.</p>
<p>Networking led us to the <a href="https://10times.com/agra-innovate">Agra Innovate</a> trade show in Lagos. An opportunity to network, market and also learn more about the business. It was at this summit I got carried away by the focus on tomato exports. At the time, the hot topic was the over 40% post-harvest loss across the tomato value chain in Nigeria. In Nigeria about 200,000 Nigerian farmers grow more than 1.8 million metric tons of tomatoes per annum on approximately 170,000 hectares, against the demand of 2.3 million MT per annum. This leaves a deficit of at least 500,000 metric tons. These post harvest losses occurred partly due to <strong>lapses in preservation, low productivity, poor transportation, near absence of commercial scale technology, imbalances in market forces as well as inadequate post-processing</strong>. These issues all came on the heel of a wide spread pest attack which had exposed the porousness of the country to looming dangers of food scarcity.&nbsp;</p>
<p>Unfortunately, tomato wasn't our primary focus at the trade event. We were focused on another cash crop - <em>Fonio</em>. However, I allowed myself soak information as i went from stall to stall, learning all i could from the event about agribusiness while marketing.</p>
<p>My experience here is noteworthy as it marked my first sojourn into agribusiness. Though unrelated, I had another short but very practical stint in animal husbandry and livestock business almost 2 years thereafter in the ancient city of Ibadan. I may someday detail that sojourn. This tale is for 2019.</p>
<p><img src="https://cdn.buttercms.com/kxiK13qqTeO1agSsbnqu" alt="play to end and reverse.gif" /></p>
<p><strong>Fig. 1 Map View of Kubau</strong></p>
<p><strong>2019 - Kubau</strong></p>
<p>Fast forward to a time in 2019, I was a freelance developer working out of a co-work space in northern Nigeria, I was mostly on my laptop ironing out JavaScript. A friend encouraged me to volunteer for a contract role as a Local Community Trainer (LCT) for an International agri based NGO undertaking a large scale agri project across mostly northern Nigeria. I leveraged on my earlier mentioned foray in agriculture which placed me in good stead.</p>
<p>At the one week training, we learned the goals of the job. That is, reducing post-harvest losses in the tomato value chain to improve smallholder farmer livelihoods in Nigeria. We were to go about this by data gathering and capture, training and retraining of local farmers, Identifying and analysing needs based reports, incentivization and the establishment of communication channels with relevant stakeholders. It sounded like boardroom stuff or the procedure for corporate marketing but this was way way localised and as I would eventually discover, more intricate. Personally, I saw an opportunity to improve my command of the local dialect(Hausa) and engagement/identification of viable business opportunity along the supply chain. It wasn't full-time but required certain amount of hours a week and this was to last through the <em>Dry season</em>. I found out it was possible to merge the time with my computing pursuits. Field days were the toughest. I buckled up for the experience.</p>
<p>We learned the art of community engagement and the necessity to understand and abide by the culture we were to face. These things were key to manoeuvring the tribal dichotomy still prevalent in these parts in order to execute the task. Some of us were familiar with the local culture. We had some indigenous people aiding the work.</p>
<p>However, it is easier said than done.</p>
<p>Thus did I begin my sojourn in <strong><em>Kubau</em></strong>.</p>
<p></p>
<p><strong>THE JOURNEY</strong></p>
<p>We were in teams. My team consisted of a group of 5 with one lead reporter(we sometimes alternate this duty). We were spread across identified communities under local government(s) bordering different states. It was at least a good 3 hours from <em>Kawo</em>, at the fringe of Kaduna main town.&nbsp; Our mode of transportation: we mostly carpooled. I must mention, it is hard to avoid wear and tear for any vehicle that undertakes a 4 hour journey on very patched-up stretch of road. Irregular car break downs got us accustomed to the public transportation that consisted of ramshackle buses, wagons and space buses at various undefined stops. Then, the aim was getting to the destination and accomplishing the objectives. Also, it is important to know the pronunciation of some bus stops to avoid getting lost. The generally spoken language is <em>Hausa</em>. In the depth of these parts, you'd barely hear a word of English spoken. We drafted reports, made observations, met up at specific times, re-strategised, acted as the link between the communities and the NGOs, while meeting our targets.</p>
<p>Similar teams were distributed across the focus areas. That is, the areas where post harvest losses were most prevalent in the farming regions of northern Nigeria.</p>
<p><img src="https://cdn.buttercms.com/PQBoI3TvQSOumwj4r5Ym" alt="screenshot.png" width="680" height="321" /></p>
<p><strong>Fig 2. Major Tomato farming states with significant Post-Harvest loss in northern Nigeria (2018)</strong></p>
<p>On field days, days like this, I shut my laptop, relegate programming to my mind, wear my boots and pick up a hoe.</p>
<p></p>
<p><strong>ENGAGEMENT</strong></p>
<p>Our first few weeks were subsumed establishing relations with the village/community/farm leaders. For effective coverage, we would split communities and target each scope in twos. Attached with well structured data templates, we probed for relevant information and assembled the data into something cohesive. Our most efficient tech was a customised android tablet, equipped with a detailed custom form app. This device had some offline capabilities that gave room for activities like farm mapping and data collation.</p>
<p>Local heads would usually inquire about our purpose and then connect us with those who can assist within the community. This would include the most literate and effectual individuals for the tasks. It is important to note that here, some of the traditional heads also serve dual functions as religious leaders. On our part, we sieved for suitable leaders and made draft assigns for the parts of the programme. We swiftly began engagement with the farmers and sensitised them on our purpose. We undertook the first of other seminars on enlightenment and then several others on; yield improvement methods, pest control, techniques and tools such as the <em>ZECC </em>setup and Zinc dryer.</p>
<p>Our meetings followed a similar path. Pass the meeting notice to stakeholder, Identify and secure the meeting location, prepare the man power, learning resources(books, pamphlets etc), then send out reminders prior to and on the event. It is worthy to note that we had to work around the farmers schedules as they had market days and days for aggregator interaction or local events and we had to make sure these things don't clash or spill over into our agenda. These meetings also involved light refreshments catered for by the project.</p>
<p>We would plan out the agenda for the seminars and then effect necessary translations even including the learning material even before our journeys. Engagement is not a one off affair but an attempt to establish, if possible, life long in roads into the select farming communities to enable growth monitoring, keep a tab on opportunities as well as provide the farmers with access to resources and information they otherwise would not have known.&nbsp;</p>
<p>How did i deal with the difficult translations? Here's a pro tip: google translate Hausa is quite an effective tool. I used it to pre evaluate discussions and responses, some of which have now become a part of my vernacular vocabulary.</p>
<p><strong><img src="https://cdn.buttercms.com/i0OPeMmMQHCDSzqCA67v" alt="undefined" width="335" height="447" /></strong></p>
<p><strong>Fig 3. On a tomato farm in Kubau</strong></p>
<p><strong></strong></p>
<p><strong>FARMING AND TECHNOLOGY</strong></p>
<p>Earlier i mentioned the <a href="https://www.britannica.com/place/Nigeria/Climate">Dry Season</a>. The Wet season covers the months of May through September in Northern Nigeria. It starts a month earlier and ends two months later in the southern Nigeria. The dry season occurred in the other months. I was engaged toward the ending of the wet season. The seasons are important in farming because they enable long term projections, help with <a href="https://en.wikipedia.org/wiki/Crop_rotation">crop rotation</a> and also determine farming schedules; planting, harvesting etc.</p>
<p>Other major cash crops grown in rotation around these parts include; peanuts (groundnuts), sugarcane, onions, soybeans, maize<em>, zobo </em>(hibiscus leaves) etc. These other cash crops play a large role in the living standard of the area and its locals. It is important to note that tomatoes and onions are perishable products but also products that are readily consumed(market availability) all year round.&nbsp;</p>
<p>Tools: The farmers made use of local farming tools and techniques as stable power is absent in these parts. The power lines also do not extend into the farming communities. This put a cap on the potential farm yields as the seasons count by. These tools include, hoes, cutlasses, sickles, shovels etc. and it is exceedingly labor intensive with farmers heading out to the farm in the mornings and coming back at sun down on farming days. Rough and inadequate landscaping also ensured that mechanical tools wouldn't perform optimally in farming processes.</p>
<p>Irrigation: Water is life and access to water for farming does make the difference between a good harvest, a poor harvest and a terrible outcome. This is why all the farmers cannot grow similar crops over time or the the same location. My community had a small lake which filled with water during the rains and dries up sometime in the dry season. This water source sometimes allowed water out and i suspect was some sort of aquifer. Farm lands located close to the river bank usually enjoyed better harvest. Capable farmers would sometimes make use of water pumping machines and really long hoses to get water into their farms. Incapable farmers made up the larger demographic and suffice to say, irrigation was grossly inadequate and low productivity, rife. In fact, irrigation made up the bulk of interest from farmers who initially mistook our mission for a charity attempt. Hence, crop choice was heavily reliant on the rains from the skies(seasons) even though arable land abound all year round. This meant that there is usually a glut during the rainy seasons when farmers want to take the most advantage of the easy produce and then a period of insufficiency during the dry seasons when farmers opt for non perishable and easier grown cash crops. These were some of the issues we sought to address.&nbsp;&nbsp;</p>
<p><img src="https://cdn.buttercms.com/95BqVPsyRhyL4bQ5yLkr" alt="undefined" width="371" height="495" /></p>
<p><strong>Fig 4. Preparing a tomato farm and Irrigation</strong></p>
<p>We weren't the only players in the game as several other players and stakeholders had existed long before we came. It is important to take note as they play many roles and influence information penetration, pricing and are also market forces influencing price, market demand and also supply. These players include <a href="https://agrilife.org/texaslocalproduce-2/files/2018/07/Tips-for-Selling-to-Aggregators-or-Grower-Marketing-Co-ops.pdf">Aggregrators</a>, <a href="https://www.investopedia.com/terms/o/offtake-agreement.asp">Offtakers</a>, Sellers etc. Prominent and established players included the Federal Government and global NGOs via the <a href="https://www.worldbank.org/en/news/feature/2010/07/28/fadama-iii-rural-agriculture-project-fast-becoming-a-household-name-in-nigeria"><em>FADAMA </em>projects</a>, <em>Babban Gona</em>(major aggregator) and local players like <em>Tomato Jos</em> amidst a host of others. Farmers usually sell to reliant aggregators or directly in the open market weekly and it is between these two that prices generally oscillate. The aggregators in turn sell to Off takers who move the goods for export or retail. These transactions are made weekly.</p>
<p>Data was conveniently gathered on all metrics and respective players. This data was outlined in Excel Sheets and custom form templates for easy aggregation of data. The farmers operated via bodies such a co-ops locally called <em>kungiya (</em>group<em>) or Kungiyoyi (</em>groups<em>).&nbsp;</em>Thus, to fine tune our activities especially those involving incentives such as access to finance, technology or policy, we operated through such co-ops facilitated by the farm heads to enable proper communication channels and access.</p>
<p>Farming Tomatoes: Tomato farming can be done on an&nbsp;<strong>open farm, greenhouses, gardens, pots and containers</strong>. Tomato fruits are then harvested after 60 &ndash; 90 days depending on the variety. Tomato seedlings are usually managed in nurseries for 3 &ndash; 4 weeks. The major varieties of tomatoes used within the farming communities involved here include;</p>
<ul>
<li>Graffiton,</li>
<li>UTC,</li>
<li>Rio</li>
</ul>
<p>... amidst others.</p>
<p>These tomatoes are harvested at the start of the <em>turning stage, </em>giving them about 7 days until full maturity. These 7 days should ideally cater for packaging from farms and then transportation to the middleman and finally to the consumer. This inevitably meant that there is a rush from harvest to get the goods out fast or stand the risk of the items actually going bad. Here i'd like to give a brief insight into transportation and farmer woes.&nbsp;</p>
<p>In the towns major city, a major market exists at the central market locally called <em>chechenya</em> market. Here is where major retail purchase is made. My farming head regaled me with the tales of farmers who will pour out their tomatoes on the floors of the market and stamp on them with tears in their eyes. Why ? Most farmers saw no need in bringing back unsold produce to their towns because they would have rot. Though this may look like a preservation problem, it is actually a market and supply issue.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p>In transporting the tomatoes, the farmers were faced with hurdles starting from the packaging of the fruit. Fruits were picked and placed in cylindrical <a href="https://bit.ly/3rTHCgo"><em>rafia baskets</em></a> of about 3 sizes ranging from big to medium which are made and sourced locally. The rafia baskets had holes made for air and are also cheap and go for about two dollars(NGN 600 - 850) at the period these events took place. These rafia baskets would be piled to the top like a mountain and are covered with cuts from jute bags to allow air flow.</p>
<p>The rafia baskets posed issues starting from sticking out rafia fibres which would pierce and damage the fruits, thereby hastening the shelf life. Also, bad tomatoes would quickly corrupt other tomatoes thereby hastening the rot process of an entire basket. Though the shape and nature of these baskets allowed for topping up extra produce as well as manoeuvrability while packing them into transport vehicles, this also meant that the produce gets squeezed and is more susceptible to heat and damage which further affects the lifespan. This was another issue we sought to address.</p>
<p><img src="https://cdn.buttercms.com/K9ZGpGeCRoSnYQY56R9b" alt="undefined" width="582" height="316" /></p>
<p><strong>Fig 5. Tomatoes in Rafia baskets set for transportation</strong></p>
<p>Security is key to farming in these parts and though unfortunate, it is important to mention long term schism between farming communities and fula herdsmen. This issue has existed probably long before i was born. It still plagues Nigeria at the time of this piece published. I got to experience it first hand, seeing farmers summoned from their sleep by local calls to rush to their farms to protect it from invaders. I also saw carefully cultivated farmlands trampled and left destroyed by herdsmen who couldn't care less but were much more focused in getting their cows fed. An issue like this is front burner in these communities and can be very easily escalated into violence.&nbsp; &nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p><strong>ISSUES</strong></p>
<p>Major issues which could be immediately tackled stemmed from the storage and preservation to the transportation processes;&nbsp;</p>
<ul>
<li>Preservation</li>
<li>Storage</li>
<li>Transportation</li>
<li>Market and Supply&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</li>
</ul>
<p><strong>SOLUTIONS AND MY PROPOSALS</strong></p>
<p>To help the farmers tackle these issues, we embarked on sensitization of farmers through regular meet ups and seminars usually hosted in the communities. Some of the solutions we proposed and facilitated were simple but highly effective.</p>
<p><strong>Preservation</strong>: Here we sought to show the farmers better techniques. The absence of electrical supply in these communities meant that electrical cold storage such as refrigeration was ruled out. However that isn't the only solution. With abundance of wood charcoal, we introduced and taught about a not well known but effective technique using of <a href="https://www.researchgate.net/publication/330323889_Effect_of_Wood_Ash_Treatment_on_Quality_Parameters_of_Matured_Green_Tomato_Fruit_Solanum_lycopersicum_L_during_Storage">wood ash in tomato storage</a> which could prolong the shelf life of tomatoes for as long as 3 months. We also sensitized the farmers on better ways to manage/handle preservation.</p>
<p><strong>Storage:</strong> Here we taught about a local way of elongating the tomatoes life span by keeping it cool before transportation. You have seen <em>ZECC</em> at the start of this write up and here we talk about it in detail. <em>ZECC</em> stands for <em>Zero Emission Cooling Chamber</em>. The ZECC is a brick construction (brick construction is popularly known for its cooling effect in building interiors), which is built by creating a rectangular space slightly below ground level. The foundation is dug slightly deeper and the brick walls are built in two columns leaving a light space between each column. This construction is then elevated to about 5 feet above ground level and then clay(known for retaining water) is used to fill up the space between both columns. All these materials are abundant in the locales including sufficient space for erecting this structure. This construction has one or two removable roof structures(depending on the size of the ZECC) which are built with rafia, wood columns and jut bag cutouts which all allow for flow of air and retaining the internal temperature. This construction can be completed in 2-3 days with all materials available. The farmers can then place tomatoes within the hollow/interior and cover with the rafia bags. The clay filling between the columns are then watered morning and night. This enabled the brick walls to have a water 24/7 and maintain temperatures of 14 degrees celsius or less. During a cold harmattan mornings, these constructions could enable 10 degrees which is sufficient to increase shelf life, control heat and improve storage for up to 14 days. This is not a new technology per say as clay pots were a known way to store cool drinking water to quench thirst in equatorial regions where temperatures could hit 40 degrees plus on hot days. I did build a ZECC with my communities and they went ahead to build 2 more during the course. I would address the use of a <em>Zinc Dryer&nbsp;</em>under Market and Supply as it indicates a new paradigm.</p>
<p><iframe width="400" height="224" src="https://www.youtube.com/embed/enOjVc-kN7Q" allowfullscreen="allowfullscreen"></iframe></p>
<p><strong><em>Vid 6. How to build a ZECC</em></strong></p>
<p><strong>Transportation:&nbsp;</strong>Though creating a new transport system, fixing horrible roads or buying new vehicles were far beyond our purview, we could however influence aspects of the process such as the cargo process. Here we introduced RPC(Returnable plastic Crates) made from plastic/rubber for storage and cargo. These were meant to be a replacement and help with phasing out for the rafia baskets and they had seemingly more advantages such as a more efficient way to stack or retrieve loaded crates in vehicles. It also kept the tomatoes better preserved as they faced less damage from heat, in storage or while in transit.</p>
<p>Unfortunately, the RPCs signified a bigger change than anticipated. Just as our current road and car width are carryovers from calculations during the era horse-drawn carriages, the rafia baskets play a major role in pricing as basket sizes not weight are a major determinant for pricing. The RPCs also cost upwards or 5 dollars even with our rebate offers. The absence of wide spread use of RPCs meant that the crates weren't actually returnable as farmers who purchased them would have to wait for delivery to get their crates back. It also meant that the farmers would need a new pricing system probably based on weight. The crates were also not easily stackable for retrieval as the bottom dimension matched the top like a square so they wouldn't sink into each other. This signified the start of poor adoption of this newer method of cargo.</p>
<p>I <strong>propose</strong> a better solution of rafia crates instead, which can be locally made. It will take repurposing the construction materials of the cylindrical baskets and designing them to carry the weight of the former. The rafia crates would still be as cheap as it is locally sourced. The bottom could be made with less width so as to enable better efficient stacking on retrieval.</p>
<p><img src="https://cdn.buttercms.com/Ot2kSonR72OVALuBYp5Z" alt="undefined" width="567" height="378" /></p>
<p><strong>Fig 7. Stacked RPC Crates</strong></p>
<p><strong></strong></p>
<p><strong>Market and Supply:&nbsp;</strong>To solve the issues of supply and market meant two things, tackle the product itself and then target inefficiencies in the demand and supply chain. Starting with the product, we introduced a way for famers to reduce their woes. By this i'm referring to the little tale i told in the farming section above. The <strong><em>Zinc Dryer </em></strong>is a type of solar dryer and <em>DIY</em> solution for repurposing rotting tomatoes which buyers and farmers alike reject and whose only former use was as fertilizer.</p>
<p>The Zinc Dryer takes advantage of the sufficient heat in these zones and the ability of Zinc in retaining this heat to create sun dried tomatoes or tomato powder. This Zinc can be sourced from local zinc roofing sheets which are in fact the cheapest roofing solutions across the country. To construct this, Zinc, wood, gauze, nails,&nbsp; metal strings and hammers are more than adequate. This structure can be built locally by creating a square wooden frame. At the bottom of the frame is a zinc sheet. A few inches above the bottom, a gauze is placed which is where the tomatoes will lie. a few inches above is another zinc sheet and above that, another zinc sheet. The effect being that as solar heat strikes the zinc sheet, it soaks the heat and passes it to the sheet below ensuring that hot air is circulated at the top layer. This heat then hits the tomatoes on the gauze below, shriveling and drying it up further. The zinc at the bottom ensures that heat isn't lost in this process but is kept circulating to further dry the tomatoes. This process can dry up tomatoes in 30 hours. Of course, there are much more efficient designs for the solar dryer but my described design above is cheap and can be done yourself in a day with the materials available.</p>
<p>The zinc dryer showcases a new paradigm as dried/powdered tomatoes isn't popular in the market even though it is still efficient and nutritious. This is due to the agrarian nature of the country and an averse nature to consuming heavily preserved perishables. Apart from that, other challenges are the final outcome whose color may take on a dull red which doesn't quite portray tomatoes as we know it. These challenges can be overcome somewhat. Whereas, products from the Zinc dryer would mean that dried tomatoes can then be exported to further markets thereby improving supply and storage.</p>
<p><strong><img src="https://cdn.buttercms.com/vQRfDASIQPOx546uxmKZ" alt="undefined" width="274" height="273" /></strong></p>
<p><strong>Fig 8. Domestic Zinc Solar Dryer</strong></p>
<p>Inefficiencies in the supply chain include barely functional transport vehicles whose regular breakdowns in inter state transportation meant shorter shelf life for the products. Hopefully with better efficient transport systems, tomatoes could be delivered by train to Benin from Kaduna in less than 24 hours rather than the lucky 48-72 hours currently attainable. I mention Benin at this point because i did attempt to introduce new supply routes to the farmers but absence of capital and risk meant that that venture had to be paused.</p>
<p></p>
<p><strong>BUSINESS AND VALUE CHAIN PROSPECTS</strong></p>
<p>In finding solutions, one cannot extricate the product in the business from the business of the product. I have mentioned ways to improve the products preservation, storage and transportation but we know change is easier said than accepted.&nbsp;</p>
<p>In improving the value chain, solar dried tomatoes if properly marketed, can be readily adopted with the right packaging. It is also cheaper and easier than processing tomatoes. It cuts out waste and produces joy for the farmer who wants nothing more than the consumption of produce in its entirety.</p>
<p>Markets abound and the dynamics of market demand and supply are ever changing. Finding new markets is also key to stabilising prices during peak and off seasons. One with the right capital and morale can identify and introduce new markets. This will also spur the farmers to grow tomatoes even during the dry seasons.</p>
<p>Greenhouses are not common in Nigeria. This is partly due to the absence of winter but more importantly, knowledge gaps on how green houses work. Before this sojourn, I was partially involved in a bamboo greenhouse project which died prematurely from lack of government interest and poor adaptation. These greenhouse made from Bamboo were cheap and efficient and if constructed in their numbers, could make a great difference in the supply chain.</p>
<p>In improving the value chain, I also propose tackling the irrigation challenges mentioned above as a lasting panacea to this issues. With the availability of aquifers across the country, boreholes can be easily sunk to get water for farming activities. Irrigation is actually the difference between sufficient supply and insufficient supply in these parts. Also the absence of power meant that farmers cannot evolve to industrial processing techniques. Though there is still much room for perfecting the current processes. Tackling these issues calls for government support and intervention though.</p>
<p>There is a lot of room for business opportunities from sale of some mentioned equipments to even sensitization. Though my sojourn here focuses on Tomatoes, these farming communities go way beyond tomato production and are deeply involved in other produce. There are viable cash crops such as soya beans etc. and quite easy ways to capitalize on the markets. For example, purchase of some cash crops during peak seasons can yield over a 100% gain if sold some months later during off season. These a just a few agribusiness tricks i got to learn during this sojourn. Of course the requisite capital and network play a huge role.</p>
<p>There are still a lot of processes that can be mechanised such as destoning of beans or in the separation of bark from crop. These processes are still carried out in very crude manners and affect the final output of the product. These are areas where capital and power supply can make a very huge difference.</p>
<p></p>
<p><strong>CONCLUSION</strong></p>
<p>My sojourn here cannot be complete without mentioning the efficacy of those i worked with from my supervisors, teammates and especially the farming communities who were receptive. I recall Hajia, who was my community farm lead. Hajia took me close and would spur farmers and hands where required to reduce the stress of the job. She also made me improve on the spoken dialect and made worthwhile introductions where necessary while enlightening us on the local field and its players. She gave me valuable information which was necessary for the success of this sojourn and my experience as well. We still speak.</p>
<p>I enjoyed local dishes such as<em> maiyan taushe and masa, </em>during stop overs with my team mates at Zaria, or snacks like <em>Tsakin</em>-<em>pate(pa-tai)</em>, <em>awara , alale, maiyan kuka </em>to mention a few which Hajia sometimes prepared or we bought after long farm days.</p>
<p>The ingenuity in farming and taking development beyond the keyboard goes beyond the farm or hectares/acres of land being used. I mentioned earlier that on non farming days, I would be back at my desk writing software code just as i'm writing this piece. In the tech hub/community back in Kaduna town, this ingenuity could also be found as agrarian kids sought solutions to farming problems at home. I got to see a young man in this tech space build an IoT device which could relay livestock data such as temperature levels, livestock count etc. to anywhere or anyone with an internet connection. A farmer could even turn on/off the lights/heating remotely via this very small device which is key in poultry farming. The prospects for technology in improving farming processes are still being pursued. Though i observe that sometimes, talented individuals such as these as sometimes snatched up by the 1st world before they have time to implement or permeate these processes.&nbsp;</p>
<p>There have been big players who have gone into farming and failed or had are rethink such as the <em>Dangote Group.</em> Worthy of mention is <em>Tomato Jos </em>which has showcased resilience and has carved a space for itself in the tomato processing and supply chain business. Nigerias import policy which enables importation of processed tomatoes also stifles market growth but should not be a determinant in going into this market. Why? because export opportunities abound and i know this from my agri experiences. One does not have to focus on the local market to be able to make proper gains. Even though i see the wisdom of free market, I support a level of control to enable local players and SMEs to survive in unmapped/rugged business terrain(s).</p>
<p>My hope is that this expos&eacute; showcases opportunities, issues and spots for improvement. It also shows that farming can be embarked on by anyone with the right drive. There is profit in the sector as a viable motive to engage and improve the community around you. Before the end of this sojourn, I had interacted with over 500 farmers, facilitated 3 ZECCs and some Zinc Dryers, made new friends and built a network within the space and enabled improvement in the agricultural processes and the community as well. Incase you feel there isn't much profit in food, I quote my sister who frequently reiterates that 'feeding can never run out of business because people just have to eat'. That being said, my foray in farming/agribusiness is far from over.&nbsp;</p>
<p>I have observed that though farming is a long term investment, sadly most people rush in for quick gains thereby loosing sight of what is important in agribusiness. Farming itself teaches patience since a method to hasten the timeline of tomato growth doesn't exist yet. It must follow the natural order as is obtainable in many other spheres of life. I would know this now, being a quasi-farmer myself.</p>
<p><strong></strong></p>
<p><strong>RESOURCES</strong></p>
<ul>
<li><a href="https://www.britannica.com/place/Nigeria/Climat">Nigerian Climate (wet and dry seasons)</a></li>
<li><a href="https://www.researchgate.net/figure/Handmade-solar-dryer-and-direct-exposure-to-solar-collector-used-in-drying-tomatoes_fig1_354118680">Zinc Solar Dryers</a></li>
<li><a href="https://nmbu.brage.unit.no/nmbu-xmlui/bitstream/handle/11250/186369/Product%20quality%20in%20solar%20dried%20carrots%2C%20tomatoes%20and%20onions.pdf?sequence=1&amp;isAllowed=y">Tomato Drying Paper</a></li>
<li><a href="https://www.aee-intec.at/0uploads/dateien553.pdf">Paper on Solar Drying</a></li>
<li><a href="https://avrdc.org/download/project-support/v4pp/training-farmers/1-5-postharvest/2_ZECC.pdf">Building a ZECC</a></li>
<li><a href="https://www.rockefellerfoundation.org/wp-content/uploads/2021/04/YieldWise-Tomato-Overview-V4.pdf">Yieldwise and TechnoServe in Nigeria</a></li>
</ul>
<p>&nbsp;</p>]]>
      </content:encoded>
      </item>
      
      <item>
         <title>Make a PHP homepage for your React App using Rewrite Rules</title>
         <link>https://sojourn.ngonike.dev/blog/use-rewrite-rules-to-make-a-php-homepage-for-your-react-app</link>
         <media:content medium="image" url="https://cdn.buttercms.com/UY0JdP1WSa2RorUjPyuk"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Mon, 15 Feb 2021 01:58:00 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/use-rewrite-rules-to-make-a-php-homepage-for-your-react-app</guid>
         <description>Why React with Cpanel and how does Shared Hosting, PHP and NGinx/Apache come into play? Here we approach server and hosting in a different way.</description>
         <content:encoded>
        <![CDATA[<p></p>
<p>You may be thinking ? Why React with PHP and how does Shared Hosting, CPanel and NGinx/Apache come into play ?</p>
<p style="text-align: justify;">Well, I possess <a href="https://en.wikipedia.org/wiki/Shared_web_hosting_service" rel="follow noopener" target="_blank" title="What is shared hosting?">shared hosting</a> which is managed via an Admin Interface known as <a href="https://www.wpbeginner.com/glossary/cpanel/" rel="follow noopener" target="_blank" title="what is Cpanel">CPanel</a>. This shared hosting houses some of my applications. When I made the decision to redesign some of my pages/services while learning React, especially as I got comfortable around the technology, I wasn't ready to move all hosting services to the cloud or otherwise even though this would have been an ideal and the trendy approach.</p>
<p style="text-align: justify;">Also, it would have been pointless shifting several running services because of a few Webpages in this case. I'd rather build out new services on the cloud and migrate the old over time. This is also because i'm quite familiar with PHP servers and still comfortable around it. Continuing to use my shared hosting also saved costs.</p>
<p style="text-align: justify;">Note that I do have services on the cloud. Also note that a lot of traditional hosting companies have moved some of their services on the cloud to take advantage of its benefits.</p>
<p style="text-align: justify;">This is not for a comparison between services but rather for a suitable work around mixing both.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</p>
<p style="text-align: justify;">Now, I'd decided to see how i can make these different technologies(ReactJS, PHP, CPanel) work together.</p>
<p style="text-align: justify;">My options for doing that included the following approaches:</p>
<p></p>
<ul>
<li>
<h4><strong>Calling React using JavaScripts <code>&lt;script&gt;</code> tag</strong></h4>
</li>
</ul>
<p style="text-align: justify;">This option allows me to sprinkle React in an existing application by calling it via JavaScripts' tag only on the pages where I require React. It can be integrated into any technology that can handle JavaScript.</p>
<p style="text-align: justify;"><strong>Pros: </strong>This is a very lightweight approach as it doesn't ship with all the weight/baggage that comes with the full React setup.</p>
<p style="text-align: justify;"><strong>Cons: </strong>If you have to ever expand Reacts functionalities within your app, you will spend time having to keep adding modules( which would have been in a full React setup ) to support your project.</p>
<p></p>
<p></p>
<ul>
<li>
<h4><strong>Using the <code>Create React App</code>&nbsp; method only</strong></h4>
</li>
</ul>
<p style="text-align: justify;">You may be familiar with the command above which creates a scaffold for a react App. This is the official out-of-the-box setup and ships with the basic dependencies you will need. It can be packaged and served via varying servers. Usually its backend service is handled with NodeJS and Express and runs mostly on the cloud.</p>
<p style="text-align: justify;"><strong>Pros:&nbsp;</strong>You don't have to keep installing dependencies and it possesses all the basic things you need to run a fully optimised React App.</p>
<p style="text-align: justify;"><strong>Cons: </strong>It can ship with the full package so it can get bulky. You probably will have dependencies you may never use. This method is also optimised specially for React so attaching disparate technologies may be a hassle.</p>
<p style="text-align: justify;"></p>
<p><strong></strong></p>
<ul>
<li>
<h4><strong>Decoupled Approach</strong></h4>
</li>
</ul>
<p style="text-align: justify;">Here, I split up the functionalities I want for only my React App such a building only the user interface(UI) layer in React, calling React only where necessary, minimising the app with React's Build command and running a different/separate backend service. Essentially a mix.</p>
<p style="text-align: justify;"><strong>Pros</strong>: Lightweight since I only make use of React where necessary. Easier to slowly implement/increase Reacts functionality across an existing system as one can add pages/services at ones own pace. Easier to integrate other existing programmers and technologies.</p>
<p style="text-align: justify;"><strong>Cons</strong>: Most suitable for programmers skilled across technologies as well as a steep learning curve getting dissimilar technologies to work together.&nbsp;</p>
<p></p>
<p></p>
<p>As you may bet, I had to go for the 3rd option. <a href="https://ashday.com/what-is-decoupled" title="What is decoupled" rel="follow noopener" target="_blank">Decoupled</a> Approach.</p>
<p></p>
<p></p>
<h3><strong>Decoupled</strong></h3>
<p style="text-align: justify;">It may interest you to know that my portfolio web application is decoupled with its blogs service as a headless CMS running on Rails in the cloud, PHP for some front and backend services and React for other parts of my UI. They're all linked together with <em>Https</em>.</p>
<p style="text-align: justify;">Hopefully, there'd be an article dedicated to the full intricacies of that journey.</p>
<p style="text-align: justify;">That article is not this article.</p>
<p style="text-align: justify;">However, this piece engages the tail-end aspects of implementing a decoupled service using the specified technologies and focuses on the Key to combining these different technologies which is where it matters most.</p>
<p></p>
<p></p>
<h3><strong>System Design</strong></h3>
<p>I went about building just the pages i needed for my react app. In my portfolio case, that was my: About, Projects and Contact Pages.&nbsp;</p>
<p>I left my homepage under PHPs service thereby keeping my entry/index/main page well connected to the rest of my existing services on the shared host.</p>
<p>A majority of my backend also remained firmly in PHP and CPanel's grasp.</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<img src="https://cdn.buttercms.com/KvMGrgOTouyjxTKEbfWl" alt="undefined" width="313" height="207" /></p>
<p></p>
<h3><strong>Build</strong></h3>
<p style="text-align: justify;">Since my homepage already existed in PHP, I had to design the UI and frontend for just my React pages.</p>
<p style="text-align: justify;">I used the Create a React App method for this so as to enable me have access to all node functionalities. I then built the pages accordingly.</p>
<p style="text-align: justify;">When you are sure your react app pages are set and ready for deployment, you should go to your <code>package.json</code>&nbsp; file in your project folder's root and change your homepage accordingly.</p>
<p style="text-align: justify;">I'm assuming here that you already have a custom domain for your application. Use this domain path for your homepage.</p>
<p style="text-align: justify;">See sample below.&nbsp;</p>
<pre class="language-undefined"><code>  "homepage": "https://mywebsite.com",</code></pre>
<p>For deployment, having certified that all my files are set, I use the <code>React Build</code> command to <a href="https://reactjs.org/docs/add-react-to-a-website.html" title="Add react to a website" rel="follow noopener" target="_blank">prepare those pages for production</a>. See the command below.</p>
<pre class="language-undefined"><code>npm run build</code></pre>
<p>This command will create a build folder of my static site but minimised and optimised only with the necessary dependencies thereby reducing app size.</p>
<p>After running this command, my React Applications files packaged in a build folder should look as below</p>
<p><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<img src="https://cdn.buttercms.com/nQdRZnWbRcu8kYR1HwGA" /></strong></p>
<p><strong></strong></p>
<p>This build folder houses your static entry page <code>index.html</code>&nbsp; . Servers like Nginx, Apache or Node (express) can be used to serve your project.</p>
<p>In our case, Nginx will handle our sites server but my hosting provider itself is powered mostly by Apache. Yes, you can mix both technologies.</p>
<p><strong></strong></p>
<h3><strong></strong></h3>
<h3><strong>Serving and Deployment</strong></h3>
<p style="text-align: justify;">In serving our project, we copy all the files in our Build folder to our projects root&nbsp; <code>public_html</code> folder.</p>
<p style="text-align: justify;">Note that we copy only the file contents and not the Build folder itself.</p>
<p style="text-align: justify;">We can achieve this using a File Transfer Protocol ( FTP ) or Secure FTP ( SFTP ) or just upload the files via CPanel using the traditional upload approach.</p>
<p style="text-align: justify;">Note that we already have an existing<strong> index.php</strong> homepage in our root folder.</p>
<p style="text-align: justify;">What your <code>public_html</code> file for a <em><strong>samplesite</strong>&nbsp;</em>should look like below.</p>
<p style="text-align: justify;"><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </strong>&nbsp;<img src="https://cdn.buttercms.com/Fs6vBEtQRQSrZHY76kcH" width="237" height="305" /></p>
<p style="text-align: justify;">It is likely that our server will naturally redirect homepage requests to <strong>index.html&nbsp;</strong>since that file trumps the <strong>index.php&nbsp;</strong>file or other files formats as well as us, having earlier specified the homepage in our <strong>package.json </strong>file in our React app.</p>
<p style="text-align: justify;">This, we do not want. So we proceed to change that below.</p>
<p><strong></strong></p>
<h3><strong>ReWrite Modules</strong></h3>
<p style="text-align: justify;">This is the Key to our aim. So pay close attention here.</p>
<p style="text-align: justify;"><span>Rewrite modules or rules change part or all of the URL in a client request. This is to inform the client of a files location or to control the flow process for file path requests.</span></p>
<p style="text-align: justify;"><span>The rewrite module rules are placed in a fil</span><span>e in our projects root i.e <code>public_html</code> . </span></p>
<p style="text-align: justify;"><span>This file is simply named <code>.htaccess</code></span></p>
<blockquote>
<p><span><b>.htaccess file</b>&nbsp;is a powerful website&nbsp;<b>file</b> that controls high-level configuration of your website. On servers that run Apache and Nginx, the .<b>htaccess file</b> allows you to make changes to your website's configuration </span><span>without having to edit server configuration <b>files.</b></span></p>
</blockquote>
<p style="text-align: justify;">This file will also resides at the very top, at our projects root folder.</p>
<p style="text-align: justify;"><strong>If </strong>we were to make our react app as the homepage, we would simply paste the code below which tells our server to serve Reacts <code>index.html</code> static file as our homepage.</p>
<p style="text-align: justify;">Note that the <code>.htaccess</code> code below is sufficient to serve your React app straightaway on the server.</p>
<p style="text-align: justify;">See below.&nbsp;</p>
<pre class="language-undefined"><code>&lt;IfModule mod_rewrite.c&gt;

  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]

&lt;/IfModule&gt;</code></pre>
<p>However,</p>
<p style="text-align: justify;">this is not just what we want.</p>
<p style="text-align: justify;">We already have a homepage which is in PHP. We do not want our React entry page as our homepage.</p>
<p></p>
<blockquote>
<p>We want our already existing <code>index.php</code> file to serve as our homepage.</p>
</blockquote>
<p></p>
<p style="text-align: justify;">To achieve this, we add some extra rules( dir_module ) to the top of our <strong>.htaccess</strong> file.</p>
<p style="text-align: justify;">Take note of the file content and where we place the <strong>index.php&nbsp;</strong>within the code.</p>
<p style="text-align: justify;">These rules identify the Directory's index. The first specifying the homepage and the second indicates the alternative homepage for our Reacts app.</p>
<p style="text-align: justify;">They also specify the file types and the Rewrite conditions. An in-depth review of these codes are beyond our scope.&nbsp;&nbsp;</p>
<p>See below.</p>
<pre class="language-undefined"><code>&lt;IfModule dir_module&gt;
 
   DirectoryIndex index.php index.html
   RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.(html|htm|php|php3|php5|shtml|phtml) [NC]
   RewriteRule ^index\.html|htm|php|php3|php5|shtml|phtml$ / [R=301,L]

&lt;/IfModule&gt;

&lt;IfModule mod_rewrite.c&gt;

  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]

&lt;/IfModule&gt;</code></pre>
<p></p>
<p>Voila! Save the file and visit your homepage in your favorite browser. Your <code>index.php</code> should appear as your homepage if you did it right. You can link that page to your static site with <em>Https</em>.</p>
<p></p>
<p><strong>Take Home</strong></p>
<p style="text-align: justify;">The rules specified in the code above will redirect the homepage of our application to the Directory Index first specified within the code.</p>
<p style="text-align: justify;">The second rules in the same file enable the react app to be served and to work appropriately via our server.</p>
<p style="text-align: justify;">We can also use the ReWrite modules to specify Error page redirects ( 404 ) or other such network protocols.&nbsp;</p>
<p></p>
<p></p>]]>
      </content:encoded>
      </item>
      
      <item>
         <title>Getting a Hang Of  State In React: A UI Challenge</title>
         <link>https://sojourn.ngonike.dev/blog/understanding-state-in-react</link>
         <media:content medium="image" url="https://cdn.buttercms.com/kqCuCDDmSJenLk2D3Lsd"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Wed, 20 Jan 2021 07:47:00 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/understanding-state-in-react</guid>
         <description>Familiarising myself with React came with some knowledge gaps I had to fill. State is a powerful and important concept at Reacts core. This piece offers a guide to understanding state through a practical approach.</description>
         <content:encoded>
        <![CDATA[<h1>Display&nbsp; Dynamic&nbsp; Information&nbsp; From&nbsp; One&nbsp; Column Of&nbsp; A&nbsp; Page&nbsp; To&nbsp; Another Column&nbsp; On&nbsp; The&nbsp; Same&nbsp; Page</h1>
<p style="text-align: justify;">A while ago I started learning React by applying the technology to personal projects. I soon realised that familiarising myself with its concepts didn&rsquo;t come without its hurdles.&nbsp;&nbsp;</p>
<p style="text-align: justify;">I eventually understood how one of Reacts foundational concepts; <strong>state</strong>, works.&nbsp;&nbsp;</p>
<p style="text-align: justify;">This article uses solving a challenge to simplify State as a concept in React to a basic form which an intermediate developer and React beginner should understand. I also explore its implementation using props in this tutorial. This article will enable the reader to easily grasp some of the concepts I tackled.</p>
<p style="text-align: justify;">This article hinges on the application of UI in tackling the challenge. To fully grasp this article, one must already be familiar with the set up of React, &nbsp;HTML, CSS, JSX(JavaScript XML) and JavaScript (JS) ES6+ syntax. However there is still guidance on basic setup herein.</p>
<p style="text-align: justify;">The skill level required to understand this article is listed below.</p>
<p style="text-align: justify;">Skill Level :</p>
<ul>
<li>ReactJS: Beginner</li>
<li>Software Development: Intermediate</li>
</ul>
<p>The predisposed reader should also have encountered:</p>
<ul>
<li>Bash Terminal, Node Package Manager (NPM) and Git</li>
</ul>
<p></p>
<p>By the end of this article, the ardent reader should understand what State in React is about and even conjure a basic UI implementation using Props.</p>
<p>I go about this article by way of an example. I present a simple challenge I encountered learning React and how going about its solution improved my knowledge of State.&nbsp;&nbsp;</p>
<p></p>
<h2><strong>Challenge </strong>&nbsp;</h2>
<p>Enable dynamic display of different information on the left column from varying card components on the right column of the same page on the click of the Image Card/Button.</p>
<p></p>
<p>See Figure 1 below.</p>
<p></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<img src="https://cdn.buttercms.com/s1fJpmiSVuFg8NTYegIo" alt="undefined" width="509" height="339" style="font-family: sans-serif;" />&nbsp; &nbsp;</p>
<p style="text-align: left;"><em><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Figure 1</strong></em>: Our Goal</p>
<p></p>
<p></p>
<h2><strong></strong></h2>
<h2><strong>React Intro&nbsp;</strong></h2>
<p style="text-align: justify;">React in this case is a technology. A type of software championed by facebook which serves the function of improving display UI(User Interface) and UX(User eXperience). It is a library that facilitates easy storage, retrieval and reuse of UI components across a software project. React is known for its speed as it reduces webpage load time significantly through some software magic I&rsquo;m not about to <a href="https://www.quora.com/Why-is-ReactJS-so-popular" rel="follow">go into</a> as that goes beyond our focus.</p>
<p style="text-align: justify;">React is straight forward at this point and is quite popular in development circles.</p>
<p>This challenge is encapsulated within a Sandbox to abstract build irrelevancies. This tutorial will still carry those working in an IDE terminal along.</p>
<p>... and so, we begin our journey at the Terminal.&nbsp; We can navigate to the folder where we'd like to house our project or head home using the <strong><em>cd</em></strong> command(CMD) -</p>
<pre class="language-undefined"><code>$ cd /home</code></pre>
<p>it could also be</p>
<pre class="language-undefined"><code>$ cd /home/desktop</code></pre>
<p>OR&nbsp;</p>
<pre class="language-undefined"><code>$ cd /htdocs</code></pre>
<p>depending on where we normally house our projects.</p>
<p>In our parent folder is where the engine begins by the push of the CMD -</p>
<pre class="language-undefined"><code>$ create React App my-app</code></pre>
<p><br />this generates a general file structure for the folder <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>my-app</em></strong></span> (this could be any name you wish) in our chosen IDE as shown below</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img src="https://cdn.buttercms.com/BcUlphITaa4Mgy0pSdRW" />&nbsp;&nbsp;</p>
<p><em><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Figure 2: Default Folder Structure</strong></em></p>
<p>the eventual/final file structure of this sample will turn out like this below</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img src="https://cdn.buttercms.com/IQd9VuqnRaG2oNQPyCBG" width="293" height="385" />&nbsp;&nbsp;</p>
<p><em><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Figure 3: Final Folder Structure</strong></em></p>
<p>This tutorial would be conducted mainly in the <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/src</em></strong></span>&nbsp;folder.</p>
<p>Next, we clear out extra generated files irrelevant to this project and strip our scaffold to the bare minimum.</p>
<p>Just what we need. We take out:</p>
<ul>
<li>app.test.js</li>
<li>index.css</li>
<li>logo.svg&nbsp;</li>
</ul>
<p>The bash command to execute this is :</p>
<pre class="language-undefined"><code>$ rm app.test.js index.css logo.svg</code></pre>
<p></p>
<h2><strong></strong></h2>
<p><strong></strong></p>
<h2><strong>APPROACHING THE SOLUTION</strong></h2>
<p style="text-align: justify;">In tackling React, we break down our entire code into <a href="https://www.w3schools.com/react/react_components.asp" rel="follow noopener" target="_blank">components</a>. This facilitates ease of understanding our code by segmenting the relationships between different design features. This little project is uses 2 components: <strong>SideBarInfo.js</strong>&nbsp;and <strong>Thumbnail.js</strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p style="text-align: justify;">Our entry page is the file <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/src/App.js</em></strong></span><span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em></em></strong></span></p>
<p style="text-align: justify;">These are most of what we need and what we'd be working with.</p>
<p style="text-align: justify;">The stylesheets needed are added to the various folders where their related files are housed; <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/src</em></strong></span> and&nbsp; <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/Components</em></strong></span>/&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p style="text-align: justify;">We'd go further into the stylesheets below.<strong></strong></p>
<p style="text-align: justify;"></p>
<p></p>
<h2><strong>Design</strong></h2>
<p style="text-align: justify;">The idea is to be able to click on an <strong>Item</strong> from the <strong>COLUMN 2</strong> on the right and have expanded details about it appear on <strong>COLUMN 1&nbsp;</strong>on the left.</p>
<p style="text-align: justify;">Keep the Columns in mind as we'd refer to them throughout this piece.</p>
<p></p>
<p>See figure below</p>
<p></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<img src="https://cdn.buttercms.com/tdm3C9MRQ0yvXVLn7DDT" width="432" height="306" /></p>
<p><em><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Figure 4: UI MockUp for our Intended Design</strong></em></p>
<p></p>
<p style="text-align: justify;"></p>
<p style="text-align: justify;"></p>
<p style="text-align: justify;">by the design above, we can break down the single page into two columns. This can be achieved by CSS in the stylesheet( <strong>styles.css</strong> ) . Let's house this in our <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/src</em></strong></span>&nbsp;folder</p>
<p style="text-align: justify;">we can create the styles file via the terminal with the CMD</p>
<pre class="language-undefined"><code>$ touch styles.css</code></pre>
<p style="text-align: justify;">We populate our <strong>styles.css&nbsp;</strong>file with the design parameters defining our column and classes for the left and the right. This stylesheet would later be invoked in our main page&nbsp; <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>../App.js </em></strong></span>&nbsp;via JavaScripts import function.</p>
<pre class="language-css"><code>/* styles.css file */

.column {
  padding: 10px;
  height: 250px;
}

.left {
  float: left;
  display: block;
  width: 35%;  
}

.right {
  float: right;
  display: block;
  width: 65%;
}
</code></pre>
<p><strong></strong></p>
<p><strong></strong></p>
<h2><strong>Components</strong></h2>
<p></p>
<p style="text-align: justify;">Now we have our page split in 2 different columns, we can proceed to break down what goes into each column.</p>
<p style="text-align: justify;">The <strong>left</strong> column ( <strong>COLUMN 1</strong> ) will house our first component which is the view for the <strong>SideBarInfo</strong> which shows details of a clicked item including its corresponding Image and name</p>
<p style="text-align: justify;">from the <strong>right</strong> column ( <strong>COLUMN</strong> <strong>2</strong> ) which houses our second component which is the <strong>Thumbnail&nbsp;</strong>that shows an Item <em>Image</em> and its <em>Name</em>.</p>
<p style="text-align: justify;">Keep in mind that Item List will be stored in an array on our main display page <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>../App.js </em></strong></span>&nbsp;and in this same file is where understanding our Props come into play ( we'd get to this later ).</p>
<p style="text-align: justify;"></p>
<p>We navigate to our <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/src</em></strong></span> folder and create the folder for our Components&nbsp;&nbsp;</p>
<pre class="language-undefined"><code>$ mkdir Components</code></pre>
<p>next we navigate to our <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/Components </em></strong></span>&nbsp;folder where we create the file components and their stylesheet with the CMDs</p>
<pre class="language-undefined"><code>$ touch SideBarInfo.js Thumbnail.js Sample.css</code></pre>
<p><strong></strong></p>
<h3><strong>Thumbnail</strong></h3>
<p style="text-align: justify;">We navigate to our <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>../Components </em></strong></span>&nbsp;folder where we focus on the thumbnail component starting with the folder css file ( Sample.css ) which we edit below. This css contains a barebones styling for our <strong>Item</strong>&nbsp;</p>
<p style="text-align: justify;">Much ado about naming conventions, we name an <strong>Item</strong> css class; <span style="text-decoration: underline;"><em>Work</em></span>&nbsp;</p>
<blockquote>
<p>furthermore, we'd be referring to <em>Item</em> and <em>Work</em>&nbsp; interchangeably since Work is how we'll be describing each Item by syntax (more on this later below )&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</p>
</blockquote>
<p style="text-align: justify;">Below, we delve into the component stylesheet that defines the parameters of what a single <strong>Item&nbsp;</strong>in&nbsp;<strong>COLUMN 2&nbsp;</strong> should look like. See below.</p>
<pre class="language-css"><code>/* Sample.css file */

.Work .image-container {
  height: 10rem;
  margin-bottom: 1rem;
  border-radius: 30px;
  display: flex;
  flex-wrap: wrap;
  position: inherit;
  width: 100%;
  max-width: 100%;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  background: #000;
}
</code></pre>
<p>Right now, we imagine a single <strong>Item </strong>to comprise of a thumbnail which houses/displays a single<em> Item Image. </em>Below this item we will display its corresponding<em> Item name </em>Information in a HTML <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>&lt;/div&gt; </em></strong></span>&nbsp;tag in our <strong>Thumbnail.js</strong> file.</p>
<p>See figure 5 below&nbsp; &nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img src="https://cdn.buttercms.com/w5pwQApSfSvhW6GFceDs" width="234" height="231" />&nbsp; &nbsp;</p>
<p><em><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Figure 5: Single Thumbnail Item</strong></em></p>
<p></p>
<p style="text-align: justify;">Done with the stylesheet, we proceed to work on the <strong>Thumbnail.js&nbsp;</strong>file, where we&nbsp;</p>
<ul>
<li style="text-align: justify;">import React&nbsp;</li>
<li style="text-align: justify;">import our stylesheet ( <strong>Sample.css</strong> )</li>
<li style="text-align: justify;">define the Work/Item Props</li>
<li style="text-align: justify;">placing the Work/Item image in a div and defining its action after a click event</li>
<li>placing the Work/item name beneath the image&nbsp;</li>
</ul>
<pre class="language-javascript"><code>import React from "react";  //standard import React function
import "./Sample.css";  // we import the sample stylesheet

//below we  create our thumbnail class for this thumbnail component

class Thumbnail extends React.Component {   
  render() {
    return (
      &lt;div&gt;
        &lt;div className="column right"&gt;
          &lt;div className="Work"  
// ES6+ onClick handles the click event for an Item Image 
              onClick={(e) =&gt; this.props.click(this.props.work)}  &gt; 

// we display the Item Image with its style class
            &lt;div className="image-container"&gt; 
              &lt;img 
                   src={this.props.work.imageSrc}  
                   alt={this.props.work.imageSrc}  /&gt; 
            &lt;/div&gt;
//  display the Items' name info 
            &lt;div className=""&gt; 
              &lt;p&gt; {this.props.work.work}&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }
}

// below we export this component making it available for use about the Application

export default Thumbnail;  
</code></pre>
<p>Having built the thumbnail Component for column 2, we proceed to build the SidebarBarInfo for <strong>COLUMN 1.</strong></p>
<p><strong></strong></p>
<h3><strong>SideBarInfo</strong></h3>
<p>We navigate back to our <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/component</em></strong></span>&nbsp;folder where we face the <strong>SideBarInfo.js&nbsp;</strong>file which will house the layout for what our <strong>COLUMN 1</strong> display will look like.</p>
<p></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<img src="https://cdn.buttercms.com/3zPjcGn3QDiWlsQyLgOg" width="232" height="306" /></p>
<p><em><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Figure 6: SideBarInfo View</strong></em></p>
<p><em><strong></strong></em></p>
<p style="text-align: justify;">Using the same stylesheet, we embark on defining the UI parameters for the SideBarInfo component below in JSX.</p>
<ul>
<li style="text-align: justify;">we import the React</li>
<li style="text-align: justify;">we import the stylesheet</li>
<li style="text-align: justify;">we define/display the image style and its prop</li>
<li style="text-align: justify;">we display the Item name and further details</li>
</ul>
<p></p>
<pre class="language-javascript"><code>/* SideBarInfo.js file */

import React from "react";  // standard import React function
import "./Sample.css";  // imports the Sample stylesheet 

// below we use a function instead of a class(both can be interchangeable depending on usage)

function SidebarInfo(props) {         
  return (
    &lt;div&gt;
      &lt;div className="Work"&gt;
        &lt;h1&gt; NAME &lt;/h1&gt;            // random header title 
        &lt;div className="image-container"&gt; // image styling here, props below
          &lt;img //image size override, new image dimensions below
            width="150"
            height="150"
            src={props.imageSrc}
            alt={props.imageSrc}
          /&gt;
        &lt;/div&gt;
        &lt;p&gt; {props.work} &lt;/p&gt; // name of the Item/Work props
        &lt;p&gt; {props.view} &lt;/p&gt; // other details:"view" of the Item/Work
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

// lastly we export the entire component file for recall/reuse across our application
export default SidebarInfo;    </code></pre>
<p></p>
<h2><strong>App.js</strong></h2>
<p style="text-align: justify;">We navigate back to our <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>/src folder </em></strong></span>&nbsp;where we turn our attention to the main page where our <strong>App</strong> component is a class.</p>
<p style="text-align: justify;">You've been reading about state from the start of this write up. It comes into play at this point where we tie our project together.&nbsp;</p>
<p style="text-align: justify;"><strong></strong></p>
<h3 style="text-align: justify;"><strong>What Is State ?</strong></h3>
<p style="text-align: justify;">I see State here as a capsule within a component which contains data that is managed within that component. State determines how a component behaves and is rendered(more on render below). Not all components have/use state and those that don't are referred to as <em>stateless</em> components while those that do are <em>stateful</em>. There are many ways a component can access and manage States' data such as the use of props, setState , useState and Hooks. An In-depth explanation is beyond the scope of this tutorial.</p>
<p style="text-align: justify;">Let's dive into how this comes in.</p>
<blockquote>
<p>So, our COLUMN 2 holds a list of items and we've designed the container for a single Item ( <strong>Thumbnail.js</strong> ) . How then do we list the items and get them to show up in our page ?</p>
</blockquote>
<p style="text-align: justify;">We begin our<strong> App.js</strong> file by establishing a Class component (App) with a Constructor method that accepts props, and has <strong><em>this.state</em></strong> which at the moment, is a container housing an empty object.</p>
<p style="text-align: justify;">This empty object would be filled with our array/list of Items and their details.</p>
<p></p>
<pre class="language-javascript"><code>class App extends React.Component {
        constructor(props) {
          super(props);
          this.state = { };   
        }
   }</code></pre>
<p style="text-align: justify;">The array of Items are to be referred to as : <em>w</em><strong><em>orks,</em>&nbsp;</strong>while a single item in the array is titled : <em><strong>work</strong></em>. Works is essentially a dummy list of our items.&nbsp;</p>
<p style="text-align: justify;"><strong>works</strong> is an array of our Items comprising of :</p>
<ul style="text-align: justify;">
<li>an Id referred to as - ' <em><strong>id</strong></em>'</li>
<li>a title known as - '<em><strong>work</strong></em>'</li>
<li>an image link known as - '<em><strong>imageSrc</strong></em>'</li>
<li>one detail known as - '<em><strong>view</strong></em>'&nbsp; &nbsp; &nbsp; ( view can hold a link or any string detail )</li>
<li>a boolean (true or false) value known as - '<em><strong>selected</strong></em>'&nbsp; ( this variable will come into play further below ).</li>
</ul>
<p style="text-align: justify;"></p>
<p style="text-align: justify;">*<strong>Note*</strong> that you feel free to add more details to your Items(Work) array, but here we use only 2 items.</p>
<p style="text-align: justify;"></p>
<p></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<img src="https://cdn.buttercms.com/uYT3o4fRgiYKckFA2BWA" alt="screenshot.png" width="285" height="287" />&nbsp;&nbsp;</p>
<p><em><strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Figure 7: View of SIdeBarInfo &amp; Items Array</strong></em></p>
<p></p>
<p></p>
<p>See what I mean below ( The image links used are sourced from Creative Commons )&nbsp;&nbsp;</p>
<pre class="language-javascript"><code>class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      works: [
        {
          id: 0,
          work: "Work 1",
          imageSrc:
            "https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=701&amp;q=80",
          view: "#",
          selected: false
        },
        {
          id: 1,
          work: "Work 2",
          imageSrc:
            "https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=701&amp;q=80",
          view: "#",
          selected: false
        }
      ]
    };
}</code></pre>
<p></p>
<p style="text-align: justify;">Now that we have our array captured in State, we can think about how to get these items showing.</p>
<p style="text-align: justify;">Time to bring in <em><strong>render() </strong></em>&nbsp;I'd briefly recall a couple of things that <strong>render()</strong> is and i'd leave out what it's not.</p>
<ul style="text-align: justify;">
<li>The <strong>render</strong> function performs the role of displaying specified code in an HTML element such as a <em><strong>&lt;div&gt; .&nbsp;</strong></em></li>
<li>It enables interaction between various components in a React application.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</li>
<li>Using a Prop, render can divulge full or parts of its State and Components' logic to other components.</li>
<li>A render is triggered once there's any change in the components state (part of the magic that makes React fast and responsive)</li>
<li>A render can be accessed by the DOM (view layer) and can relay display</li>
</ul>
<p style="text-align: justify;">In our render function for our <strong>App</strong> component, we'd display the Column layout and the Items in our State.</p>
<p style="text-align: justify;">We add the code to a render function.</p>
<p style="text-align: justify;"></p>
<p>Let's dive</p>
<pre class="language-javascript"><code>class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      works: [
        {
          id: 0,
          work: "Work 1",
          imageSrc:
            "https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=701&amp;q=80",
          view: "#",
          selected: false
        },
        {
          id: 1,
          work: "Work 2",
          imageSrc:
            "https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=701&amp;q=80",
          view: "#",
          selected: false
        }
      ]
    };

  }

// see the added Render function here below

  render() {
    return (
      &lt;div className="column "&gt; // column style class for this HTML element
        &lt;span&gt;

//NOTE- Reacts class components allows you to call in functions from the same component

// below is SideBarInfo's column (left)            
          &lt;div className="left"&gt; 
                { }    // placeholder for JSX
            &lt;/div&gt;  
// below is Thumbnail's column for Items:works array
           &lt;div className="right"&gt;  
               { }   // placeholder for JSX
           &lt;/div&gt;
        &lt;/span&gt;
      &lt;/div&gt;
    );
  }
}
</code></pre>
<p></p>
<p style="text-align: justify;">Our App component is beginning to fill out. We have our array of items stored in State, we have our Column parameters called in a render function. But we can't see much and have a bug or two.</p>
<p style="text-align: justify;">So, how do we link it all up and display i.e. our stateful <strong>App component</strong> ( that houses an array of items in state and also renders an empty column arrangement ) <strong>+</strong> our <strong>SidebarInfo</strong> functional component (which accepts a prop and returns its data)&nbsp; <strong>+</strong>&nbsp; a single lonely <strong>Thumbnail </strong>class component ( which renders an empty shell that will contain an Items data ?</p>
<p style="text-align: justify;"></p>
<blockquote>
<p style="text-align: justify;">*<strong>Tip</strong>* Class components in React accept props naturally so props doesn't need to be declared but can be called with 'this.props'. Functional components on the other hand have to declare props as in 'function(props)...{props.ObjectName}' (see SideBarInfo.js)</p>
</blockquote>
<p style="text-align: justify;"></p>
<p style="text-align: justify;">Our <strong>COLUMN 2&nbsp;&nbsp;</strong>will house our Items list which would be Thumbnails of the Items currently in our App components state.</p>
<p style="text-align: justify;">Our <strong>COLUMN 1&nbsp;</strong>will house a SideBarInfo which can display a clicked Thumbnail and all its data in our state if need be.</p>
<p style="text-align: justify;"></p>
<p style="text-align: justify;">We will use <strong>3 functions</strong> to go about the logic of linking up our components. All these functions will be in our App component which houses our State. We will call our stylesheet and the other components in our <span style="color: #7e8c8d; background-color: #ecf0f1;"><strong><em>../App.js&nbsp;</em></strong></span>&nbsp; file through JavaScripts import function as well.</p>
<p style="text-align: justify;">The functions we will use are :</p>
<ul>
<li style="text-align: justify;">makeWorks() :&nbsp; this function iterates through the <em>works </em>array and returns each items data in a thumbnail which listens for a click event</li>
<li style="text-align: justify;">handleCardClick() : this function accepts an <em>id&nbsp;</em>and <em>Thumbnail </em>( React allows you to call a global component in a function provided it has been imported ).&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; It listens for a click event and registers the id of the clicked item while changing its <em>selected&nbsp;</em>value based on the event and the storing it in state.&nbsp;</li>
<li>showWorks() :&nbsp; this functions accepts <em>works </em>, iterates through each one, picks the <em>selected</em> array and displays its data in as a <em>SideBarInfo</em> via props.&nbsp; &nbsp; &nbsp;</li>
</ul>
<p></p>
<pre class="language-javascript"><code>  makeWorks = (works) =&gt; {   
  // JavaScripts ES6 map method iterates the array of works and returns an item Thumbnail 
    return works.map((work) =&gt; {   
      return (   // returned thumbnail with useful classes and method 
        &lt;Thumbnail
          work={work}
          click={(e) =&gt; this.handleCardClick(work.id, e)}
          key={work.id}
        /&gt;
      );
    });
  };

// this function below accepts an id and Thumbnail component
  handleCardClick = (id, Thumbnail) =&gt; {   
    console.log(id);

// we define works variable below
    let works = [...this.state.works]; 

// our ternary operator below stores the boolean value in the variable
    works[id].selected = works[id].selected ? false : true;   
 
    works.forEach((work) =&gt; {  // this ES6 method ensures that unselected values are false
      if (work.id !== id) {
        work.selected = false;
      }
    });

// below we mutate our State by changing the value of selected

    this.setState({   
      works
    });
  };

// vanilla Javascript loops through the works array and uses props to display selected item/work in SideBarInfo

  showWorks = (works) =&gt; { 
    let i = 0;
    var w = [];
    while (i &lt; works.length) {
      if (works[i].selected) {
        w = works[i];
      }
      i++;
    }
    return &lt;SidebarInfo imageSrc={w.imageSrc} work={w.work} /&gt;;
  };</code></pre>
<p></p>
<p style="text-align: justify;"><strong>*Note* </strong>Recall that SideBarInfo is a functional component that accepts props. Hence we can call our data from an item in State and use it to populate SideBarInfos shell in one function. We can then return that that function in our render().&nbsp; &nbsp;[ behold JavaScript Inception ]. Likewise, Thumbnail already defines the <em>work</em> object it accepts via props so when we call it in our <strong>App</strong> component, we assign it data from our State and allow the component display it. Props are immutable and read-only and cannot be modified or changed like State.</p>
<p style="text-align: justify;">Also, recall the Constructor method ? which accepts props ? Well, our 3 functions shown above are going to go into our <strong>App</strong> Class and we will bind them to that Constructor method to make state available to these functions.&nbsp;</p>
<p style="text-align: justify;"></p>
<blockquote>
<p style="text-align: justify;">below We bind these functions together in state,</p>
<p style="text-align: justify;">call in our component and style imports,</p>
<p style="text-align: justify;">rework our <em>render()&nbsp;</em>to facilitate our display</p>
<p style="text-align: justify;">and call it a day.&nbsp;&nbsp;</p>
<p style="text-align: justify;"></p>
</blockquote>
<p>Let's dive</p>
<pre class="language-javascript"><code>// App.js

// we import components and styling below

import React from "react";
import Thumbnail from "./Components/Thumbnail";     
import SidebarInfo from "./Components/SideBarInfo";
import "./styles.css";

// below we add export method to our App Component 

export default class App extends React.Component { 
  constructor(props) {                         
    super(props);
    this.state = {
      works: [
        {
          id: 0,
          work: "Work 1",
          imageSrc:
            "https://images.unsplash.com/photo-1584608168573-b6eec7a04fd7?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=701&amp;q=80",
          view: "#",
          selected: false
        },
        {
          id: 1,
          work: "Work 2",
          imageSrc:
            "https://images.unsplash.com/photo-1581665269479-57504728e479?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=701&amp;q=80",
          view: "#",
          selected: false
        }
      ]
    };

// we bind the functions to our constructor method like this below
    this.makeWorks = this.makeWorks.bind(this);
    this.handleCardClick = this.handleCardClick.bind(this);
    this.showWorks = this.showWorks.bind(this);
  }

// here comes our functions in shining armor
  makeWorks = (works) =&gt; {
    return works.map((work) =&gt; {
      return (
        &lt;Thumbnail
          work={work}
          click={(e) =&gt; this.handleCardClick(work.id, e)}
          key={work.id}
        /&gt;
      );
    });
  };

  handleCardClick = (id, Thumbnail) =&gt; {
    console.log(id);

    let works = [...this.state.works];

    works[id].selected = works[id].selected ? false : true;

    works.forEach((work) =&gt; {
      if (work.id !== id) {
        work.selected = false;
      }
    });

    this.setState({
      works
    });
  };


  showWorks = (works) =&gt; {
    let i = 0;
    var w = [];
    while (i &lt; works.length) {
      if (works[i].selected) {
        w = works[i];
      }
      i++;
    }
    return &lt;SidebarInfo imageSrc={w.imageSrc} work={w.work} /&gt;;
  };

  render() {                                                           
    return (  
      &lt;div className="column "&gt;
        &lt;span&gt;
// The JSX below renders our showWorks()-it gives it access to state below. This displays SideBarInfo for the Left COLUMN 1
         
           &lt;div className="left"&gt;        
              {this.showWorks(this.state.works)} 
            &lt;/div&gt;

// The JSX below renders our makeWorks()-it gives it access to state here. It displays item Thumbnails for the right COLUMN 2
          &lt;div className="right"&gt;   
              {this.makeWorks(this.state.works)}  
          &lt;/div&gt;
        
        &lt;/span&gt;
      &lt;/div&gt;
    );
  }
}

// export default App; 
// using the export above is an alternative to adding it to the class above</code></pre>
<p>We can now save our files. Your /<strong>index.js</strong> file should call your App component and should look as below&nbsp;</p>
<pre class="language-javascript"><code>import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

const rootElement = document.getElementById("root");
ReactDOM.render(
  &lt;React.StrictMode&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;,
  rootElement
);
</code></pre>
<p></p>
<p></p>
<p></p>
<h3 style="text-align: justify;"><strong>RECAP</strong></h3>
<p style="text-align: justify;">This piece tackles a UI display challenge. It goes about this via props, State and onClick in React. Our final view would show a UI display akin to <strong>Figure 1.</strong></p>
<p style="text-align: justify;">Lastly, this tutorial only displays 2 items. Feel free to add more Items to your array and play around with the CSS to accommodate your own styling.&nbsp;</p>
<p></p>
<p></p>
<p><a href="https://codesandbox.io/s/modern-sky-y9d3c" rel="follow">You can view a working version of this tutorial in my SandBox&nbsp;</a></p>
<p></p>
<p></p>]]>
      </content:encoded>
      </item>
      
      <item>
         <title>Automation, Jobs &amp; Your Future</title>
         <link>https://sojourn.ngonike.dev/blog/automation-jobs-and-the-future</link>
         <media:content medium="image" url="https://cdn.buttercms.com/fqBbVDQjSFiWsn8ZHnsj"/>
         <dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">N.G. Onike</dc:creator>
         <pubDate>Tue, 13 Oct 2020 15:44:00 +0000</pubDate>
         <guid>https://sojourn.ngonike.dev/blog/automation-jobs-and-the-future</guid>
         <description>I believe in the capability of developing minds and worlds to achieve their potential. See what the future holds for labor in our world.</description>
         <content:encoded>
        <![CDATA[<p id="9a60" class="ig ih ii ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph=""><strong class="ij cj">A DEVELOPMENT PERSPECTIVE</strong></p>
<p id="27db" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">As automation through technology trudges along the course of <a href="https://www.investopedia.com/terms/m/mooreslaw.asp" rel="follow">Moores law</a> especially via electrical power, technology, artificial intelligence etc. the ripple effects are bound to be seen on the world and in your local economy especially as regards human capital, growth and labour as we embrace a new phase of industrial and human capital development.</p>
<p id="3726" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Where you position yourself now may very well impact your socio economic future. You don&rsquo;t have to live a life of frugality while existing in a world of plenty.</p>
<h1 id="8a2f" class="jf jg gl as jh ji jj im jk jl jm iq jn jo jp jq jr js jt ju jv jw jx jy jz ka dy" data-selectable-paragraph=""><strong class="bc">Labour: Toward Sustainable living.</strong></h1>
<p id="0c04" class="ig ih gl ij b ik kb im in io kc iq ir is kd iu iv iw ke iy iz ja kf jc jd je cw dy" data-selectable-paragraph="">As leaps and bounds are made across sectors including Industry, labour is receiving shock waves.</p>
<p id="0374" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">I<span id="rmm">n</span>dustry was once touted the largest employer of labour, ushering a huge new change in human living. It powered mass education via the print and greatly contributed to the world system we have today.</p>
<p id="3126" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Humans seem to have conquered the surface of the earth. Currently attempting to repair it, they look beyond, with refined technology to build a sustainable future. A future that runs itself while humans are free to pursue higher ventures beyond earth.</p>
<blockquote class="kg">
<p id="7435" class="kh ki gl as kj kk kl km kn ko kp je av" data-selectable-paragraph=""><strong class="bc">You don&rsquo;t have to live a life of frugality while existing in a world of plenty.</strong></p>
</blockquote>
<p id="004a" class="ig ih gl ij b ik kq im in io kr iq ir is ks iu iv iw kt iy iz ja ku jc jd je cw dy" data-selectable-paragraph="">There is lacunae created by the shift in labour/mindset and this can only be filled by a labour market that is largely unavailable. The assembly line form of production has been almost perfected. Labour intensive Industries like agriculture virtually don&rsquo;t rely on as many human hands to provide produce to feed millions. Optimisation of existing industries and automation of manually intensive labour hold the keys to this paradigm shift.</p>
<p id="0dce" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Already, job prospects abound in the technology sector. Professionals are required to grow this sector and as the demand for innovation increases, so do the job roles.</p>
<p id="35ff" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">First world countries are already paving the Tech sector, supplying roles that tend to pay as much as $80,000 to $150,000 per annum for example in the United States. Offers are several times above the the average wage of more traditional labour. Companies are recruiting tech specialists straight from boot camps as computer science graduates are still insufficient to fill this roles.</p>
<p id="be75" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Career shifts are seeing people who earn as low as $40,000 to $80,000 averagely, shift to the tech sector, to land better roles by boosting automation. In fact, most businesses are now attempting to automate traditional roles in order to increase their ease of business. Governments are not left out as they all attempt to automate to improve transparency and make the processes of running government leaner and faster. In an attempt to make this easier, countries such as<span>&nbsp;</span><a href="http://Digital%20Nomad%20Visa%20|%20e-Residency%20-%20What%20is%20e-Residencye-resident.gov.ee%20%E2%80%BA%20nomadvisa/" class="bn kv" rel="noopener nofollow">Estonia</a><span>&nbsp;</span>are already adopting special immigrant visa programmes for experienced foreigners to come in and build their tech sectors.</p>
<p id="21de" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">All jobs that can be automated will be automated as a matter of fact. Any job that requires the use of paper or that was affected by the print era is likely to be affected by this tech era. Every form of human communication/interaction is being automated and digitized, from our way of spoken communication to writing.</p>
<blockquote class="kg">
<p id="9fe0" class="kh ki gl as kj kk kl km kn ko kp je av" data-selectable-paragraph=""><strong class="bc">All jobs that can be automated will be automated as a matter of fact.</strong></p>
</blockquote>
<p id="b594" class="ig ih gl ij b ik kq im in io kr iq ir is ks iu iv iw kt iy iz ja ku jc jd je cw dy" data-selectable-paragraph="">Labour dependents are encouraged to learn a skill in the tech sector which will be found useful in the tech space to avail oneself of inherent opportunities. Some of these required skills which can be applied to new roles and already existing roles, include;</p>
<ul class="">
<li id="5f0f" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je kw kx ky dy" data-selectable-paragraph="">Software Developers &mdash; Front End, Back End, Full Stack</li>
<li id="1606" class="ig ih gl ij b ik kz im in io la iq ir is lb iu iv iw lc iy iz ja ld jc jd je kw kx ky dy" data-selectable-paragraph="">Machine Learning Experts</li>
<li id="46b2" class="ig ih gl ij b ik kz im in io la iq ir is lb iu iv iw lc iy iz ja ld jc jd je kw kx ky dy" data-selectable-paragraph="">Engineering &mdash; Cybersecurity, Artificial Intelligence(AI), DevOps and Cloud Architects</li>
<li id="ff41" class="ig ih gl ij b ik kz im in io la iq ir is lb iu iv iw lc iy iz ja ld jc jd je kw kx ky dy" data-selectable-paragraph="">Computer Language experts &mdash; Python, Java, JavaScript (especially) amongst others</li>
<li id="642c" class="ig ih gl ij b ik kz im in io la iq ir is lb iu iv iw lc iy iz ja ld jc jd je kw kx ky dy" data-selectable-paragraph="">Scrum Masters</li>
<li id="893c" class="ig ih gl ij b ik kz im in io la iq ir is lb iu iv iw lc iy iz ja ld jc jd je kw kx ky dy" data-selectable-paragraph="">Mobile App developers and designers</li>
<li id="f1a7" class="ig ih gl ij b ik kz im in io la iq ir is lb iu iv iw lc iy iz ja ld jc jd je kw kx ky dy" data-selectable-paragraph="">Stock and cryptocurrency trading (Derivatives)</li>
</ul>
<p id="fd1e" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">People in traditional fields e.g. medicine, engineering are learning new technology in a bid to digitise and simplify their businesses and increase return on investment. A recent example in automation pursuits includes<span>&nbsp;</span><a href="https://www.robotics.org/blog-article.cfm/5G-Powered-Medical-Robot-Performs-Remote-Brain-Surgery/213" class="bn kv" rel="noopener nofollow">remote surgery</a><span>&nbsp;</span>through mechanised surgical arms which may be controlled remotely. You may begin to imagine the effects of this on medical tourism.</p>
<p id="4ed3" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">In an extended practical application, data from human tissue identification and repetitive procedure can be gathered and analysed by AI which could subsequently sequence such procedures and eventually perform such medical procedures by itself. While we are still a long way off, humans are already growing organs which may substitute as replacement to failing body parts through<span>&nbsp;</span><a href="https://www.wired.com/story/belmonte-crispr-human-animal-hybrid-organs/" class="bn kv" rel="noopener nofollow">CRISPR, another nascent technology</a>.</p>
<blockquote class="kg">
<p id="75d3" class="kh ki gl as kj kk kl km kn ko kp je av" data-selectable-paragraph=""><strong class="bc">The future is exciting depending on your perspective.</strong></p>
</blockquote>
<p id="470a" class="ig ih gl ij b ik kq im in io kr iq ir is ks iu iv iw kt iy iz ja ku jc jd je cw dy" data-selectable-paragraph="">There&rsquo;s an underlying renaissance where human capital and living can be so optimised that with complete access to knowledge, humans may aspire for the stars rather than get lost in everlasting battles for socio-economics.</p>
<p id="ce02" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Reshaping labour can come in an example of merged fields such as a medical student who may code to create a database for storing patients data files and facilitating easier access to that data as a more familiar example.</p>
<p id="35d4" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph=""><a href="https://www.thebalancecareers.com/tech-careers-4161774" class="bn kv" rel="noopener nofollow">Learning resources are abound</a><span>&nbsp;</span>with several of them offering scholarships for interested participants. Effective MOOCs some of which I&rsquo;ve made use of include; Coursera, Udacity, Lynda, CodeAcademy, Udemy, Khan and recently LinkedIn Learning etc.</p>
<p id="afa6" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Many even offer skill paths and career prospectus on completion of programmes.</p>
<p id="53d2" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Those in the labour market are encouraged to look at this paradigm shift, not with the mindset of despair but with the outlook of opportunity in order to enable them tap into this new burgeoning sector of the labour market.</p>
<p id="83f4" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">The new labour market is accessible irrespective of age, race or location. All you have to do is to prove that you can function and execute in your chosen digital field.</p>
<p id="9fdd" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph=""><a href="https://www.bls.gov/iag/tgs/iag54.htm" class="bn kv" rel="noopener nofollow">Employment of people working in IT occupations is expected to grow 12 percent from 2014 through 2024. 488,500 jobs will be added during this period.</a></p>
<p id="bfa6" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">There are openings for career shifts such as those seeking to move from traditional to digital marketing, sales etc. In fact, these makeup the bulk of career prospects in tech. There is also the need for traditional institutions to remodel and optimize themselves to cater to new educational needs or find themselves left behind. This presents another opportunity for transformation.</p>
<h1 id="dd11" class="jf jg gl as jh ji jj im jk jl jm iq jn jo jp jq jr js jt ju jv jw jx jy jz ka dy" data-selectable-paragraph=""><strong class="bc">Human Capital and Growth &mdash; A Focus on the developing world</strong></h1>
<p id="dc9e" class="ig ih gl ij b ik kb im in io kc iq ir is kd iu iv iw ke iy iz ja kf jc jd je cw dy" data-selectable-paragraph="">The demand for softer tech skills will continue to rise as tech sectors jobs like cryptocurrency experts, have opened up the field of forex and digital currency trading to otherwise hobbyists and enthusiasts.</p>
<p id="122e" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">These soft skills have created a means of generating income and even countries with unemployed talents and third world status&rsquo; can see their GDP increase through incoming forex from available jobs in this sector.</p>
<p id="b11d" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">As an example, the increasing adaptation of<span>&nbsp;</span><a href="https://www.techrepublic.com/article/the-10-most-in-demand-tech-jobs-of-2019" class="bn kv" rel="noopener nofollow">cloud computing and cybersecurity</a><span>&nbsp;</span>will bring about increases in employment, a rise in symbiotic fields like healthcare IT, mobile networking etc. Data management as well will also contribute to improving forecasts for the information technology sector.</p>
<p id="71b7" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Governments that are interested in improvements of their economy can begin to train and export skilled labour to 1st world countries in need of skilled workers in exchange for required services rather than the current labour drain with no upsides. Training and retraining of civil servants across sectors and employment of capable experts can bring a shake up to an economy and drive growth.</p>
<blockquote class="kg">
<p id="0040" class="kh ki gl as kj kk kl km kn ko kp je av" data-selectable-paragraph="">Governments are encouraged to create enabling environments by providing incentives; from Tax breaks to Special status visas to comprehensive guidelines for remunerations as well as changes in educational curricula to create room for tech/digital fields and to help professionals grow and boost the sector.</p>
</blockquote>
<p id="fe32" class="ig ih gl ij b ik kq im in io kr iq ir is ks iu iv iw kt iy iz ja ku jc jd je cw dy" data-selectable-paragraph="">Changes aren&rsquo;t a walk in the park as 3rd world countries may find it difficult to tap into this sector due to absence of critical infrastructure such as unstable power, insecurity and economic challenges. A 3rd world leader may ask where to start from if (s)he can tap into this sector.</p>
<p id="8767" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">An appropriate reply will be to show him/her the opportunities abound in this area. Power problems can be solved by tapping into the sustainable power such as solar panels, lithium batteries and inverters.</p>
<blockquote class="kg">
<p id="d056" class="kh ki gl as kj kk kl km kn ko kp je av" data-selectable-paragraph="">In exchange for resources, leaders may negotiate for technology transfer</p>
</blockquote>
<p id="0830" class="ig ih gl ij b ik kq im in io kr iq ir is ks iu iv iw kt iy iz ja ku jc jd je cw dy" data-selectable-paragraph="">In exchange for resources, leaders may negotiate for technology transfer in the form of foundational infrastructure such as factories, training and local staff representation rather than stocks or liquid assets whose capital and profits still end up in 1st world banks.</p>
<p id="7563" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">Incubation hubs are also changing communities and what was once internet Cafes are now remodelled as hubs to grow innovation and build wealth. Governments can also create digital zones within states to build tech communities which will impact the zones around them. These zones can be quickly designed with special status&rsquo; in mind by giving them electricity to work unhindered, providing security and thereby leading to exponential transformation of environments and countries as a whole.</p>
<p id="4f45" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">This equitable arrangement will have a positive effect on urban misalignment and encourage symmetrical growth even to rural areas.</p>
<blockquote class="kg">
<p id="e07b" class="kh ki gl as kj kk kl km kn ko kp je av" data-selectable-paragraph="">Individuals from the developing world who wish to jump into the new economy will first have to build a new mindset with the understanding that labour with rewards of quality income is no longer an exclusive preserve of the regular 9&ndash;5.</p>
</blockquote>
<p id="2671" class="ig ih gl ij b ik kq im in io kr iq ir is ks iu iv iw kt iy iz ja ku jc jd je cw dy" data-selectable-paragraph="">One must then train and retrain oneself in their chosen digital field from the wealth of available resources to stay abreast and to tap into the opportunities that abound.</p>
<p id="0c82" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">The most beautiful thing about this shift in labour is that workers can work remotely from anywhere and still boost productivity.</p>
<p id="9638" class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph="">In a new world where labour is highly skilled, competitive and qualified workers largely unavailable, individuals can&rsquo;t expect expertise in one day but the rewards, especially the freedom, is worth the time and effort it takes to build a successful career in these new fields.</p>
<p class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph=""></p>
<p class="ig ih gl ij b ik il im in io ip iq ir is it iu iv iw ix iy iz ja jb jc jd je cw dy" data-selectable-paragraph=""><a href="https://gabrielonike.medium.com/automation-jobs-and-the-future-c8922da08709" title="Automation, Jobs and The Future" rel="follow noopener" target="_blank"><em>This article is originally published in Medium </em></a></p>]]>
      </content:encoded>
      </item>
      
   </channel>
</rss>
