Skip to content

Instantly share code, notes, and snippets.

View donaldpipowitch's full-sized avatar

Donald Pipowitch donaldpipowitch

View GitHub Profile
@donaldpipowitch
donaldpipowitch / README.md
Last active February 27, 2024 15:42
Type-safe query params in React with a "Hook Builder"

Everyone loves type-safe APIs nowadays, but as far as I can tell query parameters are a blind spot to most people right now.

I create a hook which uses a builder pattern a while ago, which allows you to create type-safe query parameters. It is not very polished and contains some specific use cases, that's why I hesitated to share it. But as I successfully use it for a couple of month already and (afaik) no one came up with something similar so far, I wanted to share it.

How does it look like?

import * as pp from './page-params';

type FavoriteFood = 'pizza' | 'noodles' | 'wraps' | 'hot-dogs';
@donaldpipowitch
donaldpipowitch / README.md
Last active February 18, 2024 09:43
Handle server errors in Formik

Whenever the server returns validation errors and we would set them with setFieldError they would be lost if any field would get a change or blur event. But we want to keep these kind of errors until the specific field changes. Additional we want to handle generic server errors (which are not specific to a field, but the whole form).

With these hooks field specific server side errors should be added like this:

const { setStatus } = useFormikContext();

const errors = {};
// adjust serverErrors to your own responses
// in this case they look like this: Array<{ name: string, error: string }>
@donaldpipowitch
donaldpipowitch / README.md
Last active January 12, 2024 04:07
Use GitLab Pages to deploy a Storybook per branch

It's quite straightforward to use GitLab Pages to deploy a Storybook instance per branch (and remove it whenever the branch will be removed). And yeah, it's irony to document this in a GitHub Gist 😅

You just need a .gitlab-ci.yml like this one:

stages:
  - setup
  - build-and-test
  - deployment
  - pages
@donaldpipowitch
donaldpipowitch / README.md
Last active November 13, 2023 22:08
Rewrite relative import paths with a codemod

⚠️ This is for an internal project, but shared publicly as a reference for myself.

If you want to have a general introduction how to write such a codemod have a look at this Gist from me.

What to do?

Place the usage.js and prettiermod.js in the root of the project. Run:

$ pnpm add globby@^11.0.0 @babel/traverse
@donaldpipowitch
donaldpipowitch / README.md
Created November 13, 2023 08:46
Custom ESLint Rules to support in migrating React Router v5 to v6

Use at your own risk! Feel free to modify. They were customized for our code base and help to automate 90% of the migration our big React Router v5 app.

You will notice some data-exact field on routes. Those are only needed while you have some merge requests still on v5 and some on v6. When your whole code base (including pending merge requests) is using v6 you can safely delete all those ESLint rules and you can just run a string-replace on your code base to remove data-exact="true" and data-exact="false".

My two biggest gotchas during the migration:

Regarding the first point we created this file src/components/root-routes that is also expected by one of the ESLint Rules:

@donaldpipowitch
donaldpipowitch / .gitlab-ci.yml
Last active October 18, 2023 23:10
Visual Regression Testing with Storybook Test Runner
storybook:test-runner8:
image: mcr.microsoft.com/playwright:v1.39.0-jammy
stage: build-and-test
artifacts:
expire_in: 2 weeks
when: always
paths:
- .storybook-images/__diff_output__/
- .storybook-images/__received_output__/
before_script:
@donaldpipowitch
donaldpipowitch / extension.ts
Created September 27, 2023 13:25
A VS Code extension which checks if a React component was created by styled-components.
import * as vscode from 'vscode';
import * as ts from 'typescript';
import * as path from 'path';
export function activate(context: vscode.ExtensionContext) {
const decorationType = vscode.window.createTextEditorDecorationType({
light: {
before: {
contentText: 'S.',
color: 'rgba(255, 0, 255, 0.7)',
@donaldpipowitch
donaldpipowitch / README.md
Created September 27, 2023 06:22
Storybook: Conditionally show story/canvas

In our Storybook we document components, but also whole pages. We also use the Docs addon. Sadly our Docs pages became pretty slow when a lot of documented pages were included. With the following solution we only render the first story/canvas by default and the remaining stories will only be rendered, when you click on them.

We do this by introducing a custom and component. Afterwards we can wrap every story/canvas in a ``.

@donaldpipowitch
donaldpipowitch / Lazy.tsx
Last active May 16, 2023 11:27
Lazy loading a React component with TypeScript 2.2
// this is our imaginary package "react-lazy"
import React, { Component, createElement } from 'react';
import { Redirect } from 'react-router-dom';
import { observer } from 'mobx-react';
import { observable } from 'mobx';
/**
* This is generic module interface. We assume that we can access React components.
*/
export interface FetchedModule {
@donaldpipowitch
donaldpipowitch / example.tsx
Created November 6, 2019 07:43
Mock Upload Progress with axios-mock-adapter
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
const mock = new MockAdapter(axios);
// this mocks a request which is always at 40% progress
mock.onPost('/upload-1').reply((config) => {
const total = 1024; // mocked file size
const progress = 0.4;
if (config.onUploadProgress) {