Skip to content

Commit

Permalink
Merge pull request #7 from pheralb/next
Browse files Browse the repository at this point in the history
🚀 tRPC v10 + @tanstack/react-query
  • Loading branch information
pheralb authored Nov 25, 2022
2 parents 5371135 + 200ed30 commit a04dd55
Show file tree
Hide file tree
Showing 20 changed files with 319 additions and 219 deletions.
32 changes: 17 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "slug",
"author": "@pheralb_",
"description": "A URL shortener built with T3 Stack",
"version": "2.1.0",
"version": "2.1.2",
"private": true,
"scripts": {
"build": "next build",
Expand All @@ -15,23 +15,23 @@
"@headlessui/react": "1.7.4",
"@next-auth/prisma-adapter": "1.0.5",
"@prisma/client": "4.6.1",
"@trpc/client": "9.27.4",
"@trpc/next": "9.27.4",
"@trpc/react": "9.27.4",
"@trpc/server": "9.27.4",
"@tanstack/react-query": "4.16.1",
"@trpc/client": "10.1.0",
"@trpc/next": "10.1.0",
"@trpc/server": "10.1.0",
"@trpc/react-query": "10.1.0",
"@uiball/loaders": "1.2.6",
"framer-motion": "7.6.7",
"framer-motion": "7.6.10",
"nanoid": "4.0.0",
"next": "13.0.4",
"next-auth": "4.16.4",
"next": "13.0.5",
"next-auth": "4.17.0",
"next-seo": "5.14.1",
"nextjs-progressbar": "0.0.16",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.4",
"react-hook-form": "7.39.5",
"react-hot-toast": "2.4.0",
"react-icons": "4.6.0",
"react-query": "3.39.2",
"superjson": "1.11.0",
"superkey": "0.1.0-rc.9",
"zod": "3.19.1"
Expand All @@ -40,17 +40,19 @@
"@types/node": "18.11.9",
"@types/react": "18.0.25",
"@types/react-dom": "18.0.9",
"@typescript-eslint/eslint-plugin": "5.43.0",
"@typescript-eslint/parser": "5.43.0",
"@typescript-eslint/eslint-plugin": "5.44.0",
"@typescript-eslint/parser": "5.44.0",
"autoprefixer": "10.4.13",
"eslint": "8.27.0",
"eslint-config-next": "13.0.4",
"eslint": "8.28.0",
"eslint-config-next": "13.0.5",
"postcss": "8.4.19",
"prettier": "2.8.0",
"prettier-plugin-tailwindcss": "0.1.13",
"prisma": "4.6.1",
"tailwindcss": "3.2.4",
"typescript": "4.9.3"
},
"ct3aMetadata": {
"initVersion": "5.12.0"
"initVersion": "6.10.2"
}
}
4 changes: 4 additions & 0 deletions prettier.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import("prettier").Config} */
module.exports = {
plugins: [require.resolve("prettier-plugin-tailwindcss")],
};
8 changes: 1 addition & 7 deletions src/components/card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ import Modal from "@/ui/modal";
import Edit from "../functions/edit";
import Delete from "../functions/delete";

interface CardProps {
id: number;
url: string;
slug: string;
description: string;
className?: string;
}
import { CardProps } from "./interface";

const Card = (props: CardProps) => {
const [editModal, setEditModal] = useState(false);
Expand Down
7 changes: 7 additions & 0 deletions src/components/card/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface CardProps {
id: number;
url: string;
slug: string;
description: string;
className?: string;
}
38 changes: 20 additions & 18 deletions src/components/functions/create/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { useState } from "react";
import { useForm } from "react-hook-form";
import { trpc } from "@/utils/trpc";
import { CreateLinkInput } from "@/schema/link.schema";
import { BiRocket } from "react-icons/bi";
import { BiRefresh, BiRocket } from "react-icons/bi";
import { nanoid } from "nanoid";
import toast from "react-hot-toast";

import { Button } from "@/ui";
import Button from "@/ui/button";
import Alert from "@/ui/alert";

const Create = () => {
Expand All @@ -21,7 +21,7 @@ const Create = () => {
const [loading, setLoading] = useState(false);
const router = useRouter();

const { mutate, error } = trpc.useMutation(["links.create-link"], {
const { mutate } = trpc.links.createLink.useMutation({
onSuccess: () => {
router.push(`/dash`);
setLoading(false);
Expand All @@ -36,15 +36,21 @@ const Create = () => {
},
onError: () => {
setLoading(false);
setError("slug", {
type: "manual",
message: "Slug already exists. Please try another one or click 'Randomize' button.",
});
},
});

const onSubmit = (values: CreateLinkInput) => {
const areEquals = values.url === values.slug;
if (areEquals) {
return setError("slug", {
message: "The original URL and the custom URL cannot be the same",
// Check if slug & url are equals to prevent infinite redirect =>
if (values.slug === values.url) {
setError("url", {
type: "manual",
message: "The URL and the slug cannot be the same",
});
return;
}
setLoading(true);
mutate(values);
Expand All @@ -58,18 +64,13 @@ const Create = () => {

return (
<form onSubmit={handleSubmit(onSubmit)}>
{error && (
<Alert>
<p>{error.message}</p>
</Alert>
)}
<div className="mb-5">
<label htmlFor="url">Enter the URL here:</label>
<input
id="url"
type="text"
placeholder="https://"
className="rounded-md px-4 py-2 w-full focus:border-none mt-1 bg-midnightLight text-white"
className="mt-1 w-full rounded-md bg-midnightLight px-4 py-2 text-white focus:border-none"
{...register("url", {
required: {
value: true,
Expand All @@ -83,7 +84,7 @@ const Create = () => {
pattern: {
value: /^https?:\/\//i,
message:
"Please enter a valid URL. It should start with http:// or https://",
"Please enter a valid URL. It should start with https://.",
},
})}
/>
Expand All @@ -92,12 +93,12 @@ const Create = () => {
<div className="mb-5">
<label htmlFor="slug">Custom slug:</label>
<p className="text-gray-500">https://slug.vercel.app/s/</p>
<div className="flex items-center justify-between mt-1">
<div className="mt-1 flex items-center justify-between">
<input
id="slug"
type="text"
placeholder="Custom slug"
className="rounded-md px-4 py-2 w-full focus:border-none bg-midnightLight text-white"
className="w-full rounded-md bg-midnightLight px-4 py-2 text-white focus:border-none"
{...register("slug", {
required: {
value: true,
Expand All @@ -113,8 +114,9 @@ const Create = () => {
<Button
onClick={handleGenerateRandomSlug}
className="ml-2 bg-midnightLight"
icon={<BiRefresh size={17} />}
>
Random
Randomize
</Button>
</div>
{errors.slug && <Alert className="mt-2">{errors.slug.message}</Alert>}
Expand All @@ -123,7 +125,7 @@ const Create = () => {
<label htmlFor="description">Description (optional):</label>
<textarea
id="description"
className="rounded-md px-4 py-2 w-full focus:border-none mt-1 bg-midnightLight text-white"
className="mt-1 w-full rounded-md bg-midnightLight px-4 py-2 text-white focus:border-none"
{...register("description")}
/>
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/functions/delete/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const Delete = (props: DeleteProps) => {
}
}, []);

const { mutate, error } = trpc.useMutation(["links.delete-link"], {
const { mutate, error } = trpc.links.deleteLink.useMutation({
onSuccess: () => {
router.reload();
setLoading(false);
Expand Down Expand Up @@ -89,12 +89,12 @@ const Delete = (props: DeleteProps) => {
<input
type="text"
placeholder="..."
className="rounded-md px-4 py-2 w-full focus:border-none bg-midnightLight text-white"
className="w-full rounded-md bg-midnightLight px-4 py-2 text-white focus:border-none"
{...register("validate", { required: true, maxLength: 20 })}
/>
</div>
</div>
<div className="flex justify-end mt-5">
<div className="mt-5 flex justify-end">
<Button
type="submit"
disabled={loading}
Expand Down
8 changes: 4 additions & 4 deletions src/components/functions/edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const Edit = (props: EditProps) => {
const router = useRouter();
const [disabled, setDisabled] = useState(false);

const { mutate, error } = trpc.useMutation(["links.edit-link"], {
const { mutate, error } = trpc.links.editLink.useMutation({
onSuccess: () => {
router.reload();
setLoading(false);
Expand Down Expand Up @@ -69,7 +69,7 @@ const Edit = (props: EditProps) => {
type="text"
placeholder="https://"
defaultValue={props.url}
className="rounded-md px-4 py-2 w-full focus:border-none mt-1 bg-midnightLight text-white"
className="mt-1 w-full rounded-md bg-midnightLight px-4 py-2 text-white focus:border-none"
{...register("url", {
required: {
value: true,
Expand All @@ -93,15 +93,15 @@ const Edit = (props: EditProps) => {
<label htmlFor="description">Description:</label>
<textarea
id="description"
className="rounded-md px-4 py-2 w-full focus:border-none mt-1 bg-midnightLight text-white"
className="mt-1 w-full rounded-md bg-midnightLight px-4 py-2 text-white focus:border-none"
defaultValue={props.description}
{...register("description")}
/>
</div>
<Alert>
<p>This action is irreversible.</p>
</Alert>
<div className="flex justify-end mt-5">
<div className="mt-5 flex justify-end">
<Button
type="submit"
disabled={loading}
Expand Down
13 changes: 11 additions & 2 deletions src/env/schema.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,17 @@ export const serverSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]),
GITHUB_ID: z.string(),
GITHUB_CLIENT_SECRET: z.string(),
NEXTAUTH_SECRET: z.string(),
NEXTAUTH_URL: z.string().url(),
NEXTAUTH_SECRET:
process.env.NODE_ENV === "production"
? z.string().min(1)
: z.string().min(1).optional(),
NEXTAUTH_URL: z.preprocess(
// This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
// Since NextAuth automatically uses the VERCEL_URL if present.
(str) => process.env.VERCEL_URL ?? str,
// VERCEL_URL doesnt include `https` so it cant be validated as a URL
process.env.VERCEL ? z.string() : z.string().url()
),
});

/**
Expand Down
33 changes: 2 additions & 31 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import type { AppType } from "next/dist/shared/lib/utils";
import type { Session } from "next-auth";

// tRPC =>
import type { AppRouter } from "@/server/router";
import { withTRPC } from "@trpc/next";
import { httpBatchLink } from "@trpc/client/links/httpBatchLink";
import { loggerLink } from "@trpc/client/links/loggerLink";
import { trpc } from "@/utils/trpc";

// Auth =>
import { SessionProvider } from "next-auth/react";
Expand All @@ -26,9 +23,6 @@ import nextSeoConfig from "next-seo.config";
// Next progress =>
import NextNProgress from "nextjs-progressbar";

// Superjson =>
import superjson from "superjson";

const MyApp: AppType<{ session: Session | null }> = ({
Component,
pageProps: { session, ...pageProps },
Expand Down Expand Up @@ -56,27 +50,4 @@ const MyApp: AppType<{ session: Session | null }> = ({
);
};

const getBaseUrl = () => {
if (typeof window !== "undefined") return "";
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
return `http://localhost:${process.env.PORT ?? 3000}`;
};

export default withTRPC<AppRouter>({
config({ ctx }) {
const url = `${getBaseUrl()}/api/trpc`;
return {
links: [
loggerLink({
enabled: (opts) =>
process.env.NODE_ENV === "development" ||
(opts.direction === "down" && opts.result instanceof Error),
}),
httpBatchLink({ url }),
],
url,
transformer: superjson,
};
},
ssr: false,
})(MyApp);
export default trpc.withTRPC(MyApp);
3 changes: 2 additions & 1 deletion src/pages/api/trpc/[trpc].ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createNextApiHandler } from "@trpc/server/adapters/next";

import { env } from "@/env/server.mjs";
import { appRouter } from "@/server/router";
import { createContext } from "@/server/router/context";
Expand All @@ -9,7 +10,7 @@ export default createNextApiHandler({
onError:
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(`[api/trpc/] ❌ tRPC failed on ${path}: ${error}`);
console.error(`❌ tRPC failed on ${path}: ${error}`);
}
: undefined,
});
Loading

1 comment on commit a04dd55

@vercel
Copy link

@vercel vercel bot commented on a04dd55 Nov 25, 2022

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

slug – ./

slug-git-main-pheralb.vercel.app
slug.vercel.app
slug-pheralb.vercel.app

Please sign in to comment.