Skip to content

Commit

Permalink
Update to Data Structure and Programmatically Create Initial Client P…
Browse files Browse the repository at this point in the history
…ages (#13)

* Update to data and programatically create pages

* Update Compny Logos

* Initial client pages -> Header, Hero, Footer

Co-authored-by: Joshua Balloch <joshuaballoch@users.noreply.github.com>

---------

Co-authored-by: Joshua Balloch <joshuaballoch@users.noreply.github.com>
  • Loading branch information
RuairiKerins and joshuaballoch committed Sep 24, 2024
1 parent 7526b53 commit e6f73e8
Show file tree
Hide file tree
Showing 15 changed files with 321 additions and 25 deletions.
50 changes: 50 additions & 0 deletions gatsby-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const path = require("path")

exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const clientPageTemplate = path.resolve(`src/templates/clientPage.js`)
// Query for markdown nodes to use in creating pages.
// You can query for whatever data you want to create pages for e.g.
// products, portfolio items, landing pages, etc.
// Variables can be added as the second function parameter
return graphql(`
query PastClients {
allPastClientsJson(filter: {live: {eq: true}}) {
edges {
node {
name
slug
heroText
logoSrc {
id
publicURL
childImageSharp {
gatsbyImageData
}
}
sections {
title
content
}
}
}
}
}
`, { limit: 1000 }).then(result => {
if (result.errors) {
throw result.errors
}

result.data.allPastClientsJson.edges.forEach(edge => {
let client = edge.node

return ( createPage({
path: `clients/${client.slug}`,
component: clientPageTemplate,
context: {
client: client
},
}))
})
})
}
27 changes: 18 additions & 9 deletions src/components/PastClients.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React from "react";
import { GatsbyImage } from "gatsby-plugin-image";
import EmblaAutoScrollCarousel from "./embla/EmblaAutoScrollCarousel";
import { graphql, useStaticQuery } from "gatsby";
import { graphql, useStaticQuery, Link } from "gatsby";

const OPTIONS = { slidesToScroll: "auto", loop: true };

const ClientLogo = ({alt, publicURL, childImageSharp}) => {
if (childImageSharp) {
return (
<GatsbyImage
className="h-full xs:h-auto xs:w-full aspect-square rounded-2xl"
className="h-full xs:h-auto xs:w-full aspect-square"
imgStyle={{
objectFit: "contain",
}}
Expand All @@ -19,22 +19,29 @@ const ClientLogo = ({alt, publicURL, childImageSharp}) => {
)
} else { // then it's an svg, see https://github.com/gatsbyjs/gatsby/issues/10297#issuecomment-464834529
return (
<div className="rounded-2xl overflow-hidden">
<img className="rounded-2xl" style={{ height: "100%" }} src={publicURL} alt={alt} />
<div className="overflow-hidden h-full">
<img style={{ height: "100%" }} src={publicURL} alt={alt} />
</div>
)
}
}

const PastClient = ({ name, logoSrc }) => {
const PastClient = ({ name, logoSrc, slug, live }) => {
const imgProps = {
alt: `Logo of past client company, ${name}`,
...logoSrc,
}

return (
<div className="h-full xs:h-auto xs:w-full aspect-square overflow-hidden drop-shadow-lg">
{ ClientLogo(imgProps) }
<div className="h-full xs:h-auto xs:w-full aspect-square overflow-hidden drop-shadow-lg rounded-2xl bg-white">
{live ? (
<Link to={`/clients/${slug}`}>
{ ClientLogo(imgProps) }
</Link>
) : (
ClientLogo(imgProps)
)}

</div>
)
}
Expand All @@ -46,6 +53,8 @@ const PastClients = () => {
edges {
node {
name
slug
live
logoSrc {
id
publicURL
Expand All @@ -59,8 +68,8 @@ const PastClients = () => {
}
`)

const slides = queryData.allPastClientsJson.edges.map(({ node: { name, logoSrc } }) => (
PastClient({ name, logoSrc })
const slides = queryData.allPastClientsJson.edges.map(({ node: { name, logoSrc, slug, live } }) => (
PastClient({ name, logoSrc, slug, live })
))

return (
Expand Down
48 changes: 48 additions & 0 deletions src/components/client-pages/Hero.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';
import { ParallaxLayer } from '@react-spring/parallax';
import { GatsbyImage } from "gatsby-plugin-image";

const Hero = ({ client }) => {
const imgProps = {
alt: `Logo of past client company, ${client.name}`,
...client.logoSrc,
}

return (
<div className={`flex flex-col min-h-dvh w-full justify-center items-center hero-${client.slug}`}>
<div className="flex flex-col items-center w-full">
{HeroImage(imgProps)}
<div className={`font-light m-auto mb-20 sm:text-xl text-center px-8 md:px-0 md:w-3/4 lg:w-1/2 2xl:w-1/3 `}>
{client.heroText.map(paragraph => {
return (
<p className="mb-5">
{paragraph}
</p>
)
})}
</div>
</div>
</div>
);
};

const HeroImage = ({alt, publicURL, childImageSharp}) => {
if (childImageSharp) {
return (
<GatsbyImage
className="w-full md:w-1/2 lg:w-1/3 mx-auto"
imgStyle={{
objectFit: "scale-down",
}}
image={childImageSharp.gatsbyImageData}
alt={alt}
/>
)
} else { // then it's an svg, see https://github.com/gatsbyjs/gatsby/issues/10297#issuecomment-464834529
return (
<img className="w-full sm:w-1/2 lg:w-1/3 mx-auto" src={publicURL} alt={alt} />
)
}
}

export default Hero;
6 changes: 3 additions & 3 deletions src/components/layout/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import AccessibilityWrapper from "./AccessibilityWrapper";

const commonWidthClasses = "max-w-6xl mx-auto px-4 md:px-6 lg:px-8";

const Layout = ({ children }) => {
const Layout = ({ children, fullWidth = false }) => {
return (
<>
<AccessibilityWrapper>
<Header className={commonWidthClasses} />
<main className={`${commonWidthClasses} text-black`}>{children}</main>
<Footer className={commonWidthClasses} />
<main className={`${fullWidth ? '' : commonWidthClasses} text-black`}>{children}</main>
<Footer className={`${fullWidth ? '' : commonWidthClasses}`}/>
</AccessibilityWrapper>
</>
);
Expand Down
176 changes: 167 additions & 9 deletions src/data/past-clients.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,180 @@
[
{
"logoSrc": "../images/client-logos/walden.svg",
"name": "Walden Local"
"name": "Walden Local",
"slug": "walden",
"heroText": [
"Walden Local Meat works directly with small-acreage farmers throughout the North-East, providing locally-grown, sustainable, humanely-raised meat to families via their subscription share program."
],
"sections": [
{
"title": "Challenge",
"content": [
[
"Thimble connected with Walden in late 2019, at a time when lengthening development cycles were leading Walden to feel unable to evolve the product offerings and core experience available its customers."
],
[
"Thimble helped Walden overcome this slowdown by standardizing and simplifying its technology footprint. We helped assess their tech challenges and charted out how the business could adapt to run on a standard e-comm platform. We successfully worked through this migration, partnering with stakeholders to adapt the necessary parts of the business’ operations and member experience.",
"Leveraging these changes, we then worked with Walden to explore new product experiences for members, opening up new revenue streams while helping onboard industry-standard practices for testing, landing page optimization, data warehousing and dev ops."
]
]
},
{
"title": "Overcoming the Slowdown",
"content": [
[
"Walden’s supply chain starts directly with its farmers, stretching from processing & flash-freezing its meats to running its own warehouse and delivery fleet. It wasn’t clear internally whether the technology challenges Walden faced just reflected complexities inherent to the business, or if there was a better approach."
],
[
"Thimble’s initial engagement was to dive directly into this question and help assess these options. We onboarded into the current custom tech solutions and built up to a detailed understanding of Walden’s unique and complex operations. We laid out ways to enable simpler, more standard architectures and the key parts of the company’s product experience and operation that would be needed to enable these standardizations."
],
[
"From this, we laid out two main approaches to simplifying to the business: starting on the operations side, or starting with the e-commerce side. It was decided to opt for the e-comm first approach, on a headless BigCommerce architecture. This featured a main Walden-managed service running alongside BigCommerce, to support a few unique parts of Walden’s product and operations structure that were necessary to retain.",
"Walden was successfully migrated to this new architecture in October, 2021."
]
]
},
{
"title": "New Pastures",
"content": [
[
"With the new platform in place, we helped Walden start to flex the ability to test out new product offerings and revenue streams. We enabled Walden to allow for à la carte orders and offer holiday order experiences multiple times per year, in parallel to the base subscription. This was a significant win for the business to enable efforts to drive incremental revenue. Previously, the business could only offer one holiday order, Thanksgiving, once per year, in place of a subscription order, and had no other incremental purchase capabilities. Walden leveraged this flexibility and ultimately started running 4 holiday orders per year, in addition to growing its à la carte order revenue."
],
[
"Having built in foundations for their new setup to be adaptable to change, we helped Walden experiment with changes to their core subscription product. We enabled Walden to have the offer certain meats like lamb as an upsell to customers, and later offer seafood in their core subscription. We also helped Walden offer sign-up discounts & promotions, shift to a structure where it could offer any product in its catalog via a subscription, and deliver a complete rebranding of the customer-facing site."
],
[
"On the operations & customer experience side, we helped Walden continue to simplify by expanding and adapting the tools for these teams to be self-service. This included tools for areas like order management and delivery planning, with one example being a tool to plan for weather-based delivery delays."
],
[
"In parallel, we introduced new tooling and infrastructure to help Walden modernize its marketing and analytics departments. We introduced their first A/B testing frameworks and new product analytics tools to enable Walden to take a data-driven approach to conversion optimization and landing page improvements. We helped Walden introduce a central data warehouse to its systems and adopt new tools for extracting and organizing their analytics."
]
]
}
],
"live": true
},
{
"logoSrc": "../images/client-logos/glossier.svg",
"name": "Glossier"
"logoSrc": "../images/client-logos/glossier.png",
"name": "Glossier",
"slug": "glossier",
"heroText": [
"Glossier is a D2C brand that revolutionized the beauty industry with a refreshing ethos on beauty and a unique community-driven approach to marketing."
],
"sections": [
{
"title": "Systems for Growth",
"content": [
[
"Thimble worked with Glossier from 2019 to 2022, at the time of the company’s meteoric growth to $100M+ in revenue.",
"In our work with Glossier, we helped add and extend fulfilment systems to support the company’s growth. We also led a cross-functional initiative across Finance, Data, and Tech to resolve challenges in running the company’s bookkeeping, delivering a reliable, audit-ready data pipeline, enabling new reconciliation processes and improvements to the company’s time to month close."
]
]
},
{
"title": "Fulfilment Technology",
"content": [
[
"Leading up to 2019, Glossier’s had been managing its operations and outgoing fulfilment on a relatively limited set of systems.",
"Thimble was brought on board to help and extend to these systems, to enable Glossier to continue to scale and reduce manual work."
],
[
"Thimble initially embedded two engineers into the back-of-house tech team, working to add more automated integrations in to its fulfilment process.",
"We introduced Glossier’s first end-to-end integration to power its on-site inventory counts back to its 3PL systems. We then progressively extended these systems to continue to support Glossier’s growth, adding features to automate SKU selection, shipment planning, and more."
],
[
"We played a key role in assessing, integrating, and launching with a new 3PL partner as part of Glossier’s international expansion in the UK.",
"We also worked on system readiness for peak season, testing and optimizing existing systems in ‘19 and ‘20, and helping to put a new, higher-volume set of fulfilment systems in place for peak season ‘21."
]
]
},
{
"title": "Finance Challenges",
"content": [
[
"In 2020, Glossier’s CFO flagged urgent needs to improve how the company’s accounting processes were coping with its top-line revenue growth.",
"This included driving a faster month-close, enabling the company to run an orders-to-cash reconciliation process, and ensuring the data & processes behind Glossier’s bookkeeping be demonstrably audit-ready.",
"With finance & accounting expertise built up in our work with Casper, Thimble was able to step in to help evaluate the challenges posed and possible solutions."
],
[
"Thimble worked cross-functionally across Finance, Data, and Tech to build a deep understanding of Glossier’s financial processes and define ways to solve this challenge.",
"We then worked to build and deliver, within 6 months, a financial data pipeline that achieved the initial goals of being reliable, audit-ready, and able to support order to cash matching."
],
[
"As we brought online initial parts of the data pipeline, we worked with Data & Finance to validate the pipeline’s reliability and assist in their work to shift processes to the new system.",
"We then leveraged the data and insights from this system to identify & resolve improvements across the company’s ordering and fulfilment systems, reducing financial and tax gaps and standardizing customer experience processes, which helped the finance team reduce the company’s month-close."
]
]
}
],
"live": true
},
{
"logoSrc": "../images/client-logos/casper-logo.png",
"name": "Casper"
"logoSrc": "../images/client-logos/casper.svg",
"name": "Casper",
"slug": "casper",
"heroText": [
"Casper transformed buying a mattress into a fun and memorable experience. With an innovative approach to marketing and customer experience and as one of the first brands to skyrocket into hyper growth, Casper was for years the de facto standard-bearer of how to run a successful D2C brand.",
"Casper scaled to $500M+ in revenue within 6 years of launch and an IPO in 2020. The company was taken private in 2022."
],
"sections": [
{
"title": "Hypergrowth",
"content": [
[
"Thimble worked with Casper during its hyper growth and pre-IPO phases.",
"We helped maintain and extend its fulfilment systems to support hyper growth, and to lay foundations to assist in getting the company IPO-ready.",
"We worked across tech & finance to help deliver Casper’s first ERP integration. We also helped Casper implement its first wholesale partnerships with Target and others. We worked with Casper on these systems across two engagements, in 2016-2017 and in 2018-2019 leading up to its IPO."
]
]
},
{
"title": "Maturing Fulfilment Systems",
"content": [
[
"When Thimble was initially brought on, Casper was looking for help fostering a pragmatic approach to maintaining its larger software applications through hyper growth.",
"We embedded directly in the team, working hand in hand to iteratively extend its main applications while improving code quality, application structure, and maintainability."
],
[
"In this work, we worked to build and maintain features across the whole fulfilment domain, including features like planning the shipments for orders would be split into and where to fulfill from. We also managed integrations with warehouse partners and outgoing fulfilment providers. We also maintained customer service tools for managing orders."
],
[
"In early 2017, we also worked to enable Casper’s first wholesale partnership, with Target. Using EDI via SPS Commerce, this work integrated wholesale orders into Casper’s fulfilment and accounting systems, logging, planning and then fulfilling these orders. We later expanded on this work to enable other retail relationships with Hudson Bay Company and Amazon."
]
]
},
{
"title": "IPO-Readiness",
"content": [
[
"In mid 2016, Casper began a number of initiatives to transition to being IPO-ready, including an aim to onboard an ERP.",
"Thimble played a key leadership role in this effort, helping Casper and its ERP partner successfully integrate an ERP in a modern tech stack."
],
[
"Casper selected Oracle’s JD Edwards ERP (JDE) and an ERP consultancy for the project.",
"However, a clear roadmap of where and how to bring JDE into Casper’s existing e-comm and fulfilment systems was proving elusive, and implementation work was not yet able to begin.",
"We stepped in and worked cross-functionally with the finance department and the ERP consultants to turn the project around. In the initial work, we produced a detailed view of what data would be needed across all of Casper’s business transactions, for a successful integration. We built this view working closely with Finance to understand how Casper ran its current accounting processes. We then went step by step through each process with specialists from the ERP side to detail what entries would look like. We leveraged this work and our knowledge of Casper’s tech systems to lay out a roadmap to a successful first implementation, and then worked through each stage of the implementation to a successful launch.",
"In our second engagement with Casper we worked to further improve and expand these systems."
]
]
}
],
"live": true
},
{
"logoSrc": "../images/client-logos/florence-logo.png",
"name": "Florence"
"logoSrc": "../images/client-logos/florence.webp",
"name": "Florence",
"slug": "florence",
"heroText": [],
"sections": [],
"live": false
},
{
"logoSrc": "../images/client-logos/felcana-logo.png",
"name": "Felcana"
"logoSrc": "../images/client-logos/felcana.png",
"name": "Felcana",
"slug": "felcana",
"heroText": [],
"sections": [],
"live": false
}
]
Binary file removed src/images/client-logos/casper-logo.png
Binary file not shown.
Loading

0 comments on commit e6f73e8

Please sign in to comment.