Skip to content

Commit

Permalink
Fix Tracking and Improve Types (#256)
Browse files Browse the repository at this point in the history
* Fix Tracking

* Add Tests and Comments

* Update Tracking Types

* Update Logging

* Update Server Action Types
  • Loading branch information
timoclsn authored Oct 31, 2023
1 parent 5c20c32 commit c1a6b43
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 22 deletions.
2 changes: 1 addition & 1 deletion apps/resources/app/profile/DeleteAccountButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { deleteAccount } from './actions';

export const DeleteAccountButton = () => {
const { isRunning, isSuccess, error, runAction } = useAction(deleteAccount, {
onRunAction: (test) => {},
onRunAction: () => {},
onSuccess: () => {
signOut();
},
Expand Down
2 changes: 1 addition & 1 deletion apps/resources/components/Comments/DeleteCommentButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const DeleteCommentButton = ({
}: Props) => {
const { isRunning, runAction } = useAction(deleteComment, {
onError: (error) => {
console.log(error);
console.error(error);
},
});
const handleDeleteAccount = () => {
Expand Down
10 changes: 5 additions & 5 deletions apps/resources/lib/serverActions/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useReducer, useTransition } from 'react';
import { z } from 'zod';
import { InferInputType, InferValidationErrors, ServerAction } from './server';
import { InferInputArgs, InferValidationErrors, ServerAction } from './server';

interface State<TResponse extends any, TInputSchema extends z.ZodTypeAny> {
isIdle: boolean;
Expand Down Expand Up @@ -75,7 +75,7 @@ export const useAction = <
>(
inputAction: ServerAction<TInputSchema, TResponse>,
options: {
onRunAction?: (input: InferInputType<TInputSchema>) => void;
onRunAction?: (...inputArgs: InferInputArgs<TInputSchema>) => void;
onSuccess?: (data: TResponse | null) => void;
onError?: (
error: string | null,
Expand All @@ -91,16 +91,16 @@ export const useAction = <
const [isRunning, startTransition] = useTransition();

const runAction = useCallback(
async (input: InferInputType<TInputSchema>) => {
async (...inputArgs: InferInputArgs<TInputSchema>) => {
startTransition(async () => {
dispatch({
type: 'RUN_ACTION',
});

options.onRunAction?.(input);
options.onRunAction?.(...inputArgs);

try {
const result = await inputAction(input);
const result = await inputAction(...inputArgs);

// If /next/navigation function (redirect() and notFound()) is called in the action, the result will be undefined
// Skip processing because the page will be redirected
Expand Down
21 changes: 12 additions & 9 deletions apps/resources/lib/serverActions/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import {

type MaybePromise<T> = Promise<T> | T;

export type InferInputType<TInputSchema extends z.ZodTypeAny> =
z.ZodTypeAny extends TInputSchema ? void : z.infer<TInputSchema>;
// If TInputSchema is a more specific type than z.ZodTypeAny (e.g. z.ZodString),
// then we can infer the input type. Otherwise, no input is needed.
export type InferInputArgs<TInputSchema extends z.ZodTypeAny> =
z.ZodTypeAny extends TInputSchema ? [] : [input: z.infer<TInputSchema>];

export type InferValidationErrors<TInputSchema extends z.ZodTypeAny> =
z.inferFlattenedErrors<TInputSchema>['fieldErrors'];
Expand All @@ -23,25 +25,26 @@ export type ServerAction<
TInputSchema extends z.ZodTypeAny,
TResponse extends any,
> = (
input: InferInputType<TInputSchema>,
...inputArgs: InferInputArgs<TInputSchema>
) => Promise<Result<TInputSchema, TResponse>> | void;

export const createActionClient = <Context>(createClientOpts?: {
middleware?: () => MaybePromise<Context>;
}) => {
const actionBuilder = <
const createAction = <
TInputSchema extends z.ZodTypeAny,
TResponse extends any,
>(actionBuilderOpts: {
input?: TInputSchema;
action: (args: {
action: (actionArgs: {
input: z.output<TInputSchema>;
ctx: Context;
}) => MaybePromise<void> | MaybePromise<TResponse>;
}) => {
const createAction: ServerAction<TInputSchema, TResponse> = async (
input,
const action: ServerAction<TInputSchema, TResponse> = async (
...inputArgs
) => {
const [input] = inputArgs;
try {
let parsedInput = input;
if (actionBuilderOpts.input) {
Expand Down Expand Up @@ -89,8 +92,8 @@ export const createActionClient = <Context>(createClientOpts?: {
}
};

return createAction;
return action;
};

return actionBuilder;
return createAction;
};
21 changes: 21 additions & 0 deletions apps/resources/lib/serverActions/tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { z } from 'zod';
import { createActionClient } from './server';

const createAction = createActionClient();

const action = createAction({
input: z.string(),
action: () => {},
});

// @ts-expect-error
action();
action('string');

const action2 = createAction({
action: () => {},
});

action2();
// @ts-expect-error
action2('string');
8 changes: 4 additions & 4 deletions apps/resources/lib/tracking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ interface TrackingEvents {
}

export const track = <TEventKey extends keyof TrackingEvents>(
event: TEventKey,
...data: TrackingEvents[TEventKey] extends null
? []
: [TrackingEvents[TEventKey]]
...args: TrackingEvents[TEventKey] extends null
? [event: TEventKey]
: [event: TEventKey, data: TrackingEvents[TEventKey]]
) => {
const [event, data] = args;
splitbee.track(event, data);
};
4 changes: 2 additions & 2 deletions apps/resources/lib/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const withUser = async <TData extends Data>(data: TData) => {
const user = users.find((user) => user.id === data.userId);

if (!user) {
console.log(`User (${data.userId}) not found`);
console.error(`User (${data.userId}) not found`);
}

return {
Expand All @@ -43,7 +43,7 @@ export const withUserCollection = async <TData extends Data>(
const user = users.find((user) => user.id === element.userId);

if (!user) {
console.log(`User (${element.userId}) not found`);
console.error(`User (${element.userId}) not found`);
}

return {
Expand Down

1 comment on commit c1a6b43

@vercel
Copy link

@vercel vercel bot commented on c1a6b43 Oct 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.