How I Built a SoFresh-Inspired Food App from Scratch (After Doubting Myself)


https://sofresh-food-website.vercel.app/
How It All Started From “Can You Build This?” to Opening VS Code
It all began with a simple message that didn’t feel so simple at the time:
“I need you to build this for me”
along with a link to SoFresh Nigeria’s website.
My first reaction? I laughed. Then I squinted. Then I panicked just a little.
I remember typing back:
“It’s 500k oo 😩😩”
And the response?
“100k if you can design it like that perfectly.”
That sentence haunted me in the best way. Not because of the money. But because someone believed I could do it, even when I wasn’t sure myself.
🧠 The Doubts Hit Hard
I started thinking:
“What if I try and it looks nothing like it?”
“Can I really handle the layout, styling, category filtering… all that?”
“What if they’re disappointed?”
But I pushed all that aside and opened VS Code anyway.
I told myself, “You don’t have to build everything today. Just start something. Start anywhere.”
And let me use this part to say this:
To anyone reading this, especially if you're a developer who's ever looked at a finished product and thought,
There’s no way I can build that…
I want you to know something:
You don’t have to know it all to begin.
I didn’t.
In fact, I doubted myself every step of the way.
But I showed up anyway—one div, one useState, one style at a time.
You might not get it right on the first try.
It might not look perfect.
You’ll break things. You’ll fix things. You’ll search Stack Overflow more than you care to admit.
But every little step adds up.
So don’t wait for confidence.
Don’t wait for permission.
Don’t wait for perfection.
Just start. Start messy. Start scared. But please start.
Because that’s how you grow.
📝 Planning the Project
Before I even wrote a line of code, I did something different this time:
I studied the actual SoFresh website. I looked at
The layout of the homepage
The way food categories were displayed
How the food items were shown on cards
The color scheme and fonts
The order flow experience
I took notes. Sketched a wireframe. And began listing the components I’d need:
✅ Navbar
✅ Category Section
✅ Food Item Cards
✅ Cart or Order List
✅ Checkout Section (PlaceOrder)
✅ Responsive Layout
Then I asked myself a big question:
How do I manage state properly for something this big?
This wasn’t just a mini side project; it had real functionality, multiple components, data flow, and interaction. I needed something scalable.
I chose Redux.
Not because I was already great at it, honestly; I was still figuring it out, but because I wanted this project to push me out of my comfort zone.
And it did.
I was literally learning Redux Toolkit as I built.
Breaking things, reading docs, debugging my store setup, and slowly connecting all the dots in my head.
What I didn’t realize at the time was
This project was teaching me as much as I was building it.
And unknowingly, it was saving me from two big traps:
Tutorial hell and self-doubt.
That’s what this app became for me:
A living, breathing proof that I actually knew more than I thought I did; I just hadn’t tested myself yet.
The First Milestone
One of the most empowering moments?
When I got the food category section
styled to scroll horizontally like the real SoFresh website.
It wasn’t pixel-perfect, but it was functional and beautiful.
And for the first time during the project, I said to myself:
You’re really doing this. Not copying, building
How I Organized My Project Structure
For this project, I didn’t go too deep into a crazy folder architecture. I just made sure every component had its own folder and grouped similar files together for clarity.
Here’s what my actual src/
folder looked like:
📦 src
├── 📁 AddToCart
│ └── AddToCart.jsx
├── 📁 Carts
│ └── Cart.jsx
├── 📁 Checkout
│ └── Checkout.jsx
├── 📁 DiscountExplores
│ └── Discountexplore.jsx
├── 📁 Explore
│ └── Explore.jsx
├── 📁 FindUs
│ └── Location.jsx
├── 📁 Footer
│ └── Footer.jsx
├── 📁 Get
│ └── Get.jsx
├── 📁 Heros
│ └── Hero.jsx
├── 📁 Latest
│ └── Latest.jsx
├── 📁 Menu
│ └── Menu.jsx
├── 📁 Navbar
│ └── Navbar.jsx
├── 📁 NavMealPlan
│ └── NavMeal.jsx
├── 📁 SofreshStory
│ ├── SofreshStory.jsx
│ └── TheStory.jsx
├── 📁 SoFreshLifestyleBlog
│ ├── SoFreshLifeStyleBlog.jsx
│ ├── HealthyIndul.jsx
│ └── FeelingTired.jsx
└── App.jsx
I imported everything into App.
jsx and routed them using. react-router-dom
This structure helped me keep things clean while still being flexible enough to grow the app.
.
Routing Setup with
react-router-dom
One of the fun parts of this project was setting up navigation between different sections of the app using
react-router-dom
. This allowed me to create a single-page application (SPA) where users can move through the app smoothly without full page reloads.Here’s what my
App.jsx
looked like at a glance:
import React from 'react'; import { Routes, Route } from 'react-router-dom'; import Navbar from './Navbar/Navbar'; import Footer from './Footer/Footer'; import Hero from './Heros/Hero'; import Explore from './Explore/Explore'; import DiscountExplore from './DiscountExplores/Discountexplore'; import Latest from './Latest/Latest'; import SofreshStory from './SofreshStory/SofreshStory'; import TheStory from './SofreshStory/TheStory'; import Get from './Get/Get'; import Menu from './Menu/Menu'; import Location from './FindUs/Location'; import NavMeal from './NavMealPlan/NavMeal'; import CartComponent from './Carts/Cart'; import SoFreshLifeStyleBlog from './SoFreshLifestyleBlog/SoFreshLifeStyleBlog'; import HealthyIndul from './SoFreshLifestyleBlog/HealthyIndul'; import FeelingTired from './SoFreshLifestyleBlog/FeelingTired'; import AddToCart from './AddToCart/AddToCart'; import CheckoutPage from './Checkout/Checkout'; function App() { return ( <> <Navbar /> <Routes> <Route path="/" element={<Hero />} /> <Route path="/explore" element={<Explore />} /> <Route path="/discount" element={<DiscountExplore />} /> <Route path="/latest" element={<Latest />} /> <Route path="/story" element={<SofreshStory />} /> <Route path="/the-story" element={<TheStory />} /> <Route path="/get" element={<Get />} /> <Route path="/menu" element={<Menu />} /> <Route path="/location" element={<Location />} /> <Route path="/nav-meal" element={<NavMeal />} /> <Route path="/cart" element={<CartComponent />} /> <Route path="/lifestyle-blog" element={<SoFreshLifeStyleBlog />} /> <Route path="/healthy-indulgence" element={<HealthyIndul />} /> <Route path="/feeling-tired" element={<FeelingTired />} /> <Route path="/add-to-cart" element={<AddToCart />} /> <Route path="/checkout" element={<CheckoutPage />} /> </Routes> <Footer /> </> ); } export default App;
Why I Like This Setup
Clear routing: Every section has its own path, so the app structure is super predictable.
Reusable Navbar and Footer: They’re persistent across all pages, giving users a consistent experience.
Scalable: If I want to add more pages or features later, I just import and add a new
<Route>
.
Real Challenges I Faced & How I Solved Them
Let’s be real: building the SoFresh clone wasn't just styling a few buttons and calling it a day. I faced real, gritty challenges that had me second-guessing myself more than once.
Here are a few moments that almost broke me (but didn’t):
1. Building the Cart 🛒 Logic from Scratch with Context API
What went wrong:
Setting up a working cart system wasn’t as easy as adding items to an array. I had to manage quantities, avoid duplicates, update totals in real-time, and make sure state flowed across all the cart pages.
How I fixed it:
I built a custom CartContext using React’s Context API, with , addToCartremoveFromCart
, and deleteFromCart
functions that handled everything neatly.
Here’s a snippet:
const addToCart = (product) => {
const isAlreadyInCart = cartItems.find(item => item.id === product.id);
if (isAlreadyInCart) {
setCartItems(cartItems.map(item =>
item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item
));
} else {
setCartItems([...cartItems, { ...product, quantity: 1 }]);
}
};
It looks clean now, but trust me the first version was a mess of useState
chaos and broken logic.
2. Cart Navigation & Icons Didn’t Sync Properly
What went wrong:
I used Heroicons and a full navigation drawer with step indicators for Cart → Checkout → Complete. But icons wouldn’t highlight properly based on the route, and sometimes the UI didn’t reflect the cart count at all.
How I fixed it:
I tracked the current route using useLocation()
and set active states manually:
const location = useLocation();
const currentPath = location.pathname;
{currentPath === '/Checkout' && (
<li className="cart-nav active">
<Link to="/Checkout">Checkout Details</Link>
</li>
)}
This let me dynamically highlight the right step, even on refresh or manual entry.
3. CSS Styling Was a Nightmare
What went wrong:
Let me just say this: writing raw CSS for a full, responsive e-commerce site is brutal. I styled everything from the hamburger menu to the “Add to Cart” button manually. Thousands of lines of CSS just to get basic layouts right.
Why I didn’t use Tailwind yet:
I hadn’t learned Tailwind at the time. Looking back, this project taught me that utility-first CSS could’ve saved me countless hours.
Lesson: CSS is powerful, but writing it at scale without a utility framework is exhausting. Tailwind is next on my learning path — and honestly, I can’t wait.
4. Positioning Elements Was... a Joke?
What went wrong:
Sometimes a cart badge wouldn’t sit on the icon properly. Other times, things broke on mobile even after using media queries. I had sections overlapping each other like it was a food fight.
How I fixed it:
Trial. Error. And way too many position: absolute
hacks. 💀
Eventually, I started using Flexbox and grid more intentionally, but the pain taught me more than any YouTube tutorial could.
I faced so many challenges and unexpected bugs while building this app, but honestly, that’s what makes us real devs, right? It’s not just about writing code that works; it’s about facing the chaos, figuring things out, and pushing through till everything finally makes sense.
And one sneaky little detail that didn’t get left out in the battle? That cute bubble question component
We prioritize relationship, connection, engagement, and the well-being of our customers
Let me tell you, this thing gave me wahala 😅.
At first glance, it looks like a simple text bubble floating around the hero section but getting it to look just right across all screen sizes wasn’t a walk in the park.
I had to:
Tweak the positioning using
absolute
andtransform
just to make it float nicely.Adjust font sizes, padding, and alignment for both large screens and mobile views.
Use
flexbox
inside the bubble to make sure the text was perfectly centered and not awkwardly hanging at the top.Give it soft borders and shadows so it feels like it belongs in the design.
It took trial and error, lots of browser resizing, and scrolling through Stack Overflow, but…
Looking at what I finally pulled off here makes me genuinely happy. It’s these small touches that bring a UI to life and give it personality.
Lessons Learned
Whew! This project taught me way more than I initially expected,, not just about code, but about patience, growth, and confidence.
I learned how important component structure is, from breaking the UI into reusable, maintainable parts to making sure the right props are passed and state flows well. I learned the value of Redux Toolkit in managing state across multiple components, especially in a shopping/cart-related app. Before, global state used to scare me, but now? I’m the one in control.
Responsive design? Let’s just say I was humbled. 😂 Designing a beautiful layout is one thing, but making it scale gracefully across all devices? That's a whole discipline. I now understand how flexbox, media queries, and smart layouts can make or break a user’s experience.
Oh, and debugging? It’s now my toxic bestie. There were bugs that made me feel like giving up, but every time I fixed one, I became stronger, sharper, and even more determined. That’s the beauty of the dev life: it teaches you not just code, but character.
Motivation and Final Words
I didn’t build the SoFresh replica just to flex. I built it because I wanted to grow, to push myself, and to create something that looked as good as what real companies are putting out there.
Let me not even start to talk about how I fought NEPA and their inconsistent power supply 😅. I was showing up at school every single day, even during mini-holidays, just so I could use the light and keep pushing this project forward. The only days I didn’t go were weekends. And when our street’s light went off because of a spoiled transformer, I still didn’t give up. I kept going. And honestly? I’m grateful for those struggles. They made this win even more meaningful.
If you're reading this and you're also on your learning journey, keep going.
You will break things. You will cry. You will get stuck on “just one button.” But in the process, you’ll also realize something:
You're no longer just copying code; you’re building. You're thinking through design, planning data flow, handling user interactions, and solving problems like a real developer.
This project reminded me why I chose front-end development:
Because with just code, I can create experiences.
Because with every challenge I overcome, I become a better version of myself.
Because tech is hard, but I’m harder.
You’re not falling behind. You’re just learning.
You’re not failing. You’re just debugging.
And one day, someone will scroll past your work and say, “Wow… they really did that.”
🔗 Live Preview the App: https://sofresh-food-website.vercel.app/
I’d love to hear what you think! 💬
Please preview and drop your comment, suggestion, or feedback; it means a lot to me as I grow on this journey.
Let’s keep building, keep learning, and keep showing up!
Subscribe to my newsletter
Read articles from Celestine Assumpta Chinonso directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Celestine Assumpta Chinonso
Celestine Assumpta Chinonso
I’m a passionate front-end developer who enjoys crafting clean, responsive, and intuitive web interfaces. With a solid foundation in React, Redux Toolkit, and modern UI practices, I focus on building real-world, user-centered solutions that are both functional and visually engaging. Beyond the code, I have a genuine love for documenting my development journey, from technical wins and bugs to the lessons that shape me along the way. Writing is my way of reflecting, growing, and connecting with the wider dev community. When I’m not building or writing, you’ll likely find me watching a good movie, reading something inspiring, or brainstorming my next creative idea. This space is where I share not just my projects, but my passion for continuous learning, storytelling, and the beautiful mess that is becoming a better developer every day.