What actually happened, in full
The brief, the theming trick, the primitives other people built on, and how it shipped without ever going quiet.
What I was asked to fix
Talawa Admin is the browser portal that community organisations — clubs, congregations, volunteer groups, small non-profits — use to run themselves. The portal worked, roughly. It was just hard to find your way through: buttons that did nothing gave no sign they were disabled, and nothing adapted below desktop width.
The organisation didn't hand me a design. They handed me five constraints on how the fix was allowed to happen, and those constraints turned out to be the actual brief.
Constraint one is the hard one. A redesign branch that goes quiet for two months and comes back with forty conflicting files is a branch nobody merges. So I inverted the usual shape of the work: the redesign lived on a long-running branch, but I pulled develop into it and pushed it back out roughly every two weeks. Eight merge PRs across the summer, each small enough that someone would actually review it.
The side effect mattered more than the merges themselves. Because the new layout kept landing in develop, the other GSoC contributors were always building on it rather than against it. By the end they had extended my drawer component into two of their own without asking me for anything.
A month of not designing
Before selection and through community bonding, I didn't touch the visual design. I spent the time deleting things. The codebase had two complete design systems installed at once — Ant Design and Bootstrap — so every new screen picked one, and the picks were inconsistent. There was a src/css folder holding an unused Bootstrap 5 stylesheet while the project ran Bootstrap 4. And there were two screen-list components, SuperDashListCard and AdminDashListCard, with the same markup and the same CSS, differing only in whether a button read “Manage” or “View”.
Redesigning on top of that would have meant redesigning everything twice. So Ant Design came out entirely, the dead CSS went, the duplication got collapsed. Slower for four weeks. Much faster for the four months after.
This is also where the pattern for the rest of the project got set: when the frontend problem is actually a backend problem, go fix the backend. Organisation images were rendering as broken because the API returned relative paths like image/{fileName}, which fell apart the moment the server moved. I could have prefixed a base URL client-side. Instead I wrote the resolver in talawa-api, with tests.
One file to change the brand
A redesign is only maintainable if the next contributor can change the primary colour in one place and have it propagate. That meant Bootstrap 5, and it meant compiling Bootstrap from source instead of overriding it from outside.
Bootstrap 5 drops class-based modals for component-based ones. Doing that upgrade after the redesign would have meant migrating every newly built screen a second time — so the upgrade came first: raw button and input elements swapped for Button and Form.Control, class-based modals swapped for react-bootstrap ones, popper.js and react-modal dropped from the tree.
Then the part I'm still happiest with. Instead of shipping a stylesheet that fights Bootstrap's defaults with more specific selectors, I inserted the project's own variables between Bootstrap's functions and Bootstrap's variables. Sass takes the first definition it sees, so declaring $primary before importing Bootstrap's variables means Bootstrap builds itself in Talawa's colours. No overrides, no specificity war.
// Importing Bootstrap SCSS Functions and Mixins @import '../../../node_modules/bootstrap/scss/functions'; @import '../../../node_modules/bootstrap/scss/mixins'; // Importing Our Bootstrap SCSS Variables ← ours land first, so they win @import './variables'; // Importing Bootstrap Variables and SCSS @import '../../../node_modules/bootstrap/scss/variables'; @import '../../../node_modules/bootstrap/scss/variables-dark'; @import '../../../node_modules/bootstrap/scss/bootstrap.scss'; // Importing Our Bootstrap SCSS Overrides @import './talawa';
// Colors $primary: #31bb6b; $secondary: #707070; $success: #31bb6b; $warning: #febc59; $placeholder-bg: #f2f2f2; // Inputs and buttons — one rhythm for every control in the portal $input-bg: $placeholder-bg; $input-border-width: 0; $input-btn-padding-y: 0.7rem; $input-btn-padding-x: 1rem;
Underneath _talawa.scss sits a partial per Bootstrap component — accordion, alert, badge, breadcrumb, buttons, card, dropdown, modal, navbar, pagination, spinners, plus forms and typography. It mirrors Bootstrap's own structure deliberately, so a contributor who knows where something lives in Bootstrap knows where to change it here. The whole layer went from nothing to 31 files in a single PR, and I documented how to use it in CODE_STYLE.md in the same breath — an undocumented convention is a convention nobody follows.
One deliberate omission: I left the Organization Events screen unmigrated. Another GSoC contributor was rewriting that screen from scratch that same month, so fixing its failing tests would have been work thrown straight in the bin. I said so in the PR description instead of quietly leaving a gap.
Building the things other people build on
Constraint two asked for modular templates other contributors could use. This is the chapter where that either happened or didn't — and the file tree settles the argument.
PR #950 was the structural one. LeftDrawer and SuperAdminScreen were written from scratch, with tests. The two duplicate list cards were replaced by a single OrgListCard, and the admin-versus-superadmin decision was lifted up into the parent screen — so a card either renders or it doesn't, rather than rendering itself into a disabled state. Same PR: admins had the organisation search box hidden from them for no reason I could find. Admins search for organisations too. It went back in.
The evidence that constraint two was actually met isn't in my PRs. It's in what other people did with the component afterwards.
# PR #942 — 5 Jul AdminDashListCard/ ← identical twins, one button label apart SuperDashListCard/ # PR #950 — 30 Jul both gone, three primitives in their place LeftDrawer/ OrgListCard/ SuperAdminScreen/ # PR #1006 — 24 Oct other contributors extended the drawer themselves LeftDrawer/ LeftDrawerEvent/ ← not mine LeftDrawerOrg/ ← not mine OrgListCard/ SuperAdminScreen/
Two derivative drawers I never wrote, built by contributors who didn't need to ask me how. That's the constraint met, and it's the part of the project I'd point at first.
The rest of #950 was the unglamorous half of good UI: shimmer loading states, real empty states, and no results for “<query>” messaging across the Organizations, Requests and Roles screens — so a screen with nothing on it tells you why instead of just being blank.
The last mile
The final stretch was three screens and the things that only matter once a portal is genuinely used: infinite scroll on Organizations, Requests and Users; translations across every page; a redesigned forgot-password flow; a delete-organisation modal whose colour and wording made the consequence obvious.
One small decision I'd defend in any review. The language switcher had been sitting on every single screen of the portal. Language is a set-once preference — nobody changes the language they read in halfway through approving a membership request. It moved into Settings. One extra click for the rare person who switches; a quieter header on every screen for everyone else.
Settings got restructured around the same logic: membership requests moved out to their own screen, the user-detail and credential tabs were handed to the contributor who owned that area, and what remained was the three things that genuinely belong to an organisation's settings.
PR #1006 merged to master on 24 October 2023. Its “Other information” field says, in full: GSoC 2023.
Wireframes and Figma
The redesign started as low-fidelity wireframes before any code changed — the Figma file below is where the drawer layout, the organisation cards, and the settings restructuring were worked out first.
Every screenshot, recovered
All 37 assets posted across the pull request bodies at the time of review, with the captions written around them. Click to enlarge.




































