Skip to content

Commit

Permalink
Convert files to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
karlhorky committed Oct 9, 2024
1 parent 2141caa commit 50b81f5
Show file tree
Hide file tree
Showing 17 changed files with 100 additions and 41 deletions.
4 changes: 1 addition & 3 deletions app/CookieBanner.js → app/CookieBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ export default function CookieBanner() {

// // In case you are using state variables with multiple different
// // possible types
// const [areCookiesAccepted, setAreCookiesAccepted] = useState<
// boolean | string
// >(false);
// const [areCookiesAccepted, setAreCookiesAccepted] = useState<boolean | string>(false);

useEffect(() => {
const localStorageValue = getLocalStorage('cookiePolicy');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { notFound } from 'next/navigation';
import { createAnimalInsecure } from '../../../database/animals';

export default async function CreateAnimalNaivePage(props) {
type Props = {
searchParams: Promise<{
firstName: string;
type: string;
accessory: string;
birthDate: string;
}>;
};

export default async function CreateAnimalNaivePage(props: Props) {
const animalSearchParams = await props.searchParams;

const animal = await createAnimalInsecure({
Expand Down
File renamed without changes.
File renamed without changes.
19 changes: 0 additions & 19 deletions app/fruits/[fruitId]/FruitCommentForm.js

This file was deleted.

33 changes: 33 additions & 0 deletions app/fruits/[fruitId]/FruitCommentForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use client';

import { useState } from 'react';
import createOrUpdateCookie from './actions';

type Props = {
fruitId: number;
};

export default function FruitCommentForm(props: Props) {
const [comment, setComment] = useState('');

// Option 2: If you use a function declared elsewhere, you need to define the type of `event`
// function handleChange(event: ChangeEvent<HTMLTextAreaElement>) {
// setComment(event.currentTarget.value)
// }

return (
<form>
<textarea
value={comment}
// Option 1: Inline function does not require type
onChange={(event) => setComment(event.currentTarget.value)}

// Option 2: If you use a function declared elsewhere...
// onChange={handleChange}
/>
<button formAction={() => createOrUpdateCookie(props.fruitId, comment)}>
Add comment
</button>
</form>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,33 @@ import { cookies } from 'next/headers';
import { getCookie } from '../../../util/cookies';
import { parseJson } from '../../../util/json';

export default async function createOrUpdateCookie(fruitId, comment) {
export type FruitComment = {
id: number;
comment: string;
};

export default async function createOrUpdateCookie(
fruitId: FruitComment['id'],
comment: FruitComment['comment'],
) {
// 1. get current cookie!
const fruitsCommentsCookie = await getCookie('fruitsComments');

// 2. parse the cookie value
const fruitsComments =
const fruitsComments: FruitComment[] =
fruitsCommentsCookie === undefined
? // Case A: cookie undefined
[]
: parseJson(fruitsCommentsCookie);
: parseJson(fruitsCommentsCookie)!;

// 3. edit the cookie value
const fruitToUpdate = fruitsComments.find((fruitComment) => {
return fruitComment.id === fruitId;
});

// Case B: cookie set, id doesn't exist
fruitsComments.push({ id: fruitId, comment: comment });
if (!fruitToUpdate) {
fruitsComments.push({ id: fruitId, comment: comment });
} else {
// Case C: cookie set, id exists already
fruitToUpdate.comment = comment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { getCookie } from '../../../util/cookies';
import { parseJson } from '../../../util/json';
import FruitCommentForm from './FruitCommentForm';

export default async function SingleFruitPage(props) {
type Props = {
params: Promise<{
fruitId: string;
}>;
};

export default async function SingleFruitPage(props: Props) {
const fruit = getFruit(Number((await props.params).fruitId));

const fruitCommentsCookie = await getCookie('fruitsComments');
Expand Down
File renamed without changes.
7 changes: 6 additions & 1 deletion app/layout.js → app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import './globals.scss';
import localFont from 'next/font/local';
import Link from 'next/link';
import { ReactNode } from 'react';

const geistSans = localFont({
src: './fonts/GeistVF.woff',
Expand All @@ -22,7 +23,11 @@ export const metadata = {
description: 'Generated by create next app',
};

export default function RootLayout({ children }) {
type Props = {
children: ReactNode;
};

export default function RootLayout({ children }: Props) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>
Expand Down
File renamed without changes.
File renamed without changes.
10 changes: 10 additions & 0 deletions database/animals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ export const getAnimalInsecure = cache(async (id: number) => {
id = ${id}
`;

// Alternative to destructuring: access using [0]
// const animal = (await sql<Animal[]>`
// SELECT
// *
// FROM
// animals
// WHERE
// id = ${id}
// `)[0];

return animal;
});

Expand Down
2 changes: 1 addition & 1 deletion util/cookies.js → util/cookies.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cookies } from 'next/headers';

export async function getCookie(name) {
export async function getCookie(name: string) {
const cookie = (await cookies()).get(name);
if (!cookie) {
return undefined;
Expand Down
10 changes: 0 additions & 10 deletions util/json.js

This file was deleted.

19 changes: 19 additions & 0 deletions util/json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import sjson from 'secure-json-parse';
import { FruitComment } from '../app/fruits/[fruitId]/actions';

export function parseJson(json: string | undefined) {
if (!json) return undefined;
try {
// `as` is called a type assertion
//
// This tells TypeScript that you know better about
// what the type is
//
// Slightly unsafe, because we don't really absolutely
// know what the type is coming back from sjson (it
// tells us that it is `any`)
return sjson(json) as FruitComment[];
} catch {
return undefined;
}
}
2 changes: 1 addition & 1 deletion util/math.js → util/math.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export function add(a, b) {
export function add(a: number, b: number) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new Error('Pass only numbers!');
}
Expand Down

0 comments on commit 50b81f5

Please sign in to comment.