Skip to content

Instantly share code, notes, and snippets.

@pigoz
Created November 29, 2022 09:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pigoz/2bf6bea2ddbb6e6a8e5066adac044f47 to your computer and use it in GitHub Desktop.
Save pigoz/2bf6bea2ddbb6e6a8e5066adac044f47 to your computer and use it in GitHub Desktop.
import * as E from '@fp-ts/data/Either';
import * as Z from '@effect/io/Effect';
import * as Context from '@fp-ts/data/Context';
import { pipe } from '@fp-ts/data/Function';
import {
DataFunctionArgs as DataFunctionArgs_,
// LoaderFunction,
// TypedResponse,
// AppLoadContext,
json,
LoaderArgs,
ActionArgs,
redirect,
} from '@remix-run/node';
import { useActionData, useLoaderData } from '@remix-run/react';
// import { Params } from 'react-router-dom';
/*
export declare type TypedResponse<T extends unknown = unknown> = Response & {
json(): Promise<T>;
};
import type { Params } from "react-router-dom";
An object of unknown type for route loaders and actions provided by the
server's `getLoadContext()` function.
export interface AppLoadContext {
[key: string]: unknown;
}
export interface DataFunctionArgs {
request: Request;
context: AppLoadContext;
params: Params;
}
*/
export type DataFunctionArgs = DataFunctionArgs_;
export const DataFunctionArgs = Context.Tag<DataFunctionArgs>();
export type ServerEffect<E, A extends unknown = unknown> = Z.Effect<
DataFunctionArgs,
E,
A
>;
// TODO: provide a json/useLoaderData pair that extends superjson and handles
// transparent network serialization of all @fp-ts/core types that can
// be serialized (Either and Option for sure)
export const remixrun =
<E, A extends unknown = unknown>(args: DataFunctionArgs_) =>
(effect: ServerEffect<E, A>) =>
pipe(effect, Z.provideService(DataFunctionArgs)(args), Z.unsafeRunPromise);
///////////////////////////////////////////////////////////////////////////////
// examples
export const zloadersucc = Z.sync(() => json({ b: 2 }));
export const zloader = pipe(
Z.service(DataFunctionArgs),
Z.map(({ request, params }) => {
console.log('request', request);
console.log('params', params);
console.log('context', params);
return json({ a: 1 });
}),
);
// XXX handle formData parsing with zod and fp-ts/codec
export const formData = pipe(
Z.service(DataFunctionArgs),
Z.flatMap(({ request }) =>
Z.tryCatchPromise(
() => request.formData(),
() => 'formData error' as const,
),
),
);
export const zaction = pipe(
formData,
Z.map(fd =>
fd.has('foo') ? E.right(redirect('/done')) : E.left(json({ error: 'aa' })),
),
Z.flatMap(Z.fromEither),
);
export const loader = (args: LoaderArgs) => pipe(zloader, remixrun(args));
export const action = (args: ActionArgs) => pipe(zaction, remixrun(args));
export function Page() {
const ldata = useLoaderData<typeof loader>();
const adata = useActionData<typeof action>();
ldata.a; // number
adata;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment