Skip to content

14.3 Tanstackin lisääminen pääsivulle | Antti/add-tanstack-library-index-page #62

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 38 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
32387c6
Add a new SVG image. Create a TSX file of it. Add the URL where the S…
anttiasmala Nov 6, 2024
00b7d9f
Add a logout query
anttiasmala Nov 6, 2024
64f64b6
Change spinner's color to be currentColor so its color can be changed…
anttiasmala Nov 6, 2024
a955433
Add useQuery. Add a handler for logouting inside index.tsx. Add condi…
anttiasmala Nov 6, 2024
63607c7
Remove a random Test toast
anttiasmala Nov 7, 2024
3a7c033
Change giftQuery -> fetchGiftsQuery. Add addGiftQuery. Add some condi…
anttiasmala Nov 7, 2024
21213f4
Remove a couple comments that were explaining about the sleep. Not ne…
anttiasmala Nov 7, 2024
03c2625
Add deleteGiftQuery for queries. Change closeModal's position in code…
anttiasmala Nov 7, 2024
b04dc77
Revert edits in DeleteModal.tsx. They are made into wrong branch atm
anttiasmala Nov 8, 2024
84bf6a7
Merge branch antti/add-tanstack-library-register-page into antti/add-…
anttiasmala Jan 16, 2025
27a3a42
Change the way how Gift creation request is sent
anttiasmala Jan 16, 2025
8ea3cb7
Add a QueryKey type for gift creation
anttiasmala Jan 16, 2025
3ddd6ef
Fix logout query. Disable User Modal closing if logout is in progress
anttiasmala Jan 16, 2025
d3d4884
Add a QueryKey type for logout
anttiasmala Jan 16, 2025
35f30b4
Change the URL where logging out redirects
anttiasmala Jan 17, 2025
29a742e
ESLint and fixes
anttiasmala Jan 17, 2025
a59ed04
Change onClick to not be async, should not be needed. Add handleError…
anttiasmala Jan 17, 2025
8f33262
Add Z-index 100 if account is logging out so no modal can be closed b…
anttiasmala Jan 17, 2025
f01b283
Add createGiftQuery.isPending to disabled attribute
anttiasmala Jan 17, 2025
becd2c3
Remove useShowErrorToast and error variable
anttiasmala Jan 18, 2025
93dc9af
Remove whole useGetGifts function. Remove unnecessary attributes from…
anttiasmala Jan 18, 2025
dee75a4
Merge branch antti/add-tanstack-library-register-page into antti/add-…
anttiasmala Jan 18, 2025
cf575be
Revert "Remove useShowErrorToast and error variable". Started to do i…
anttiasmala Jan 18, 2025
83b347c
Merge branch 'antti/add-tanstack-library-register-page' into antti/ad…
anttiasmala Jan 18, 2025
396693f
Change '...' loading indicator to spinning spinner
anttiasmala Jan 19, 2025
14db5bd
Refactor TODO.md and add TODO task
anttiasmala Jan 19, 2025
fd55e59
Add function errorWrapper into Button.tsx component
anttiasmala Jan 19, 2025
697af06
Add just created errorWrapper to the Button component. It will let us…
anttiasmala Jan 19, 2025
3e8cbd4
Create a new file utils/errorWrapper.ts. Move the errorWrapper from B…
anttiasmala Jan 20, 2025
92abaf9
Import errorWrapper and include it in code
anttiasmala Jan 20, 2025
2f3ed2d
Remove errorWrapper due to no usage right now
anttiasmala Jan 20, 2025
6693c10
Remove xml tag in Spinner.svg file
anttiasmala Jan 20, 2025
db8d061
Add Tanstack query cache clear functions when logging in and when log…
anttiasmala Jan 20, 2025
d8f9cac
Disable button when the gift is being added
anttiasmala Jan 20, 2025
481bc79
Update TODO.md
anttiasmala Jan 20, 2025
43cbaae
Move errorWrapper function from its own file to utilFunctions.ts
anttiasmala Jan 20, 2025
815a0f3
Delete errorWrapper file for now
anttiasmala Jan 20, 2025
7960798
Add catch for router.push
anttiasmala Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@

# Enter-näppäimellä EditModalin ja DeleteModalin hyväksyminen

### </IDEOITA>
# Jos tulee virhe vaikka lahjoja hakiessa, ehkä jokin nappula olisi hyvä tehdä, jolla voisi mahdollisesti kokeilla hakea uudestaan lahjoja

TODO:
# Kun lisää uuden lahjan / kun lahjoja haetaan, järjestetään ne uusin -> vanhin. Myöhemmin voidaan lisätä käyttäjälle mahdollisuus valita miten lahjat haluaa järjestää (vaikka vanhin -> uusin, aakkosjärjestys, ymsyms)

Lisää /pages/login.tsx:n Kirjaudu sisään -nappulaan "select-none" jottei teksti tule maalatuksi jos silmää painaa muutaman kerran liian nopeasti
# Tässä toteutustapa:const sortedArrayNewestToOldest = gifts.sort((a, b) =>new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),

Jos tulee virhe vaikka lahjoja hakiessa, ehkä jokin nappula olisi hyvä tehdä, jolla voisi mahdollisesti kokeilla hakea uudestaan lahjoja
);

Kun lisää uuden lahjan / kun lahjoja haetaan, järjestetään ne uusin -> vanhin. Myöhemmin voidaan lisätä käyttäjälle mahdollisuus valita miten lahjat haluaa järjestää (vaikka vanhin -> uusin, aakkosjärjestys, ymsyms)
### </IDEOITA>

Tässä toteutustapa:
TODO:

const sortedArrayNewestToOldest = gifts.sort(
(a, b) =>
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
);
1. Tee https://github.com/samuliasmala/lahjalista/pull/62#discussion_r1921024704 omaan branchiin

2.1 Vaihda "Kirjaudu sisään"- ja "Luo käyttäjätunnus" -nappuloihin pyörivä spinner-indikaattori "..." sijaan
2.2 Lisää /pages/login.tsx:n Kirjaudu sisään -nappulaan "select-none" jottei teksti tule maalatuksi jos silmää painaa muutaman kerran liian nopeasti
35 changes: 35 additions & 0 deletions components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,41 @@
import { ButtonHTMLAttributes } from 'react';
import { twMerge } from 'tailwind-merge';

/**
* A higher-order function that wraps a given function to handle both
* synchronous and asynchronous errors. Used to ensure that errors are
* caught in event handlers and other places where they would otherwise be
* uncaugh.
*
* @template A - The type of the arguments that the wrapped function accepts.
* @param {(...args: A) => Promise<void> | void} fn - The function to be
* wrapped. It can be either synchronous or asynchronous.
* @returns {(...args: A) => void} - A new function that wraps the original
* function and handles errors and returns a synchronous result.
*
* @example
* // Usage with an asynchronous function in click handler
* const handleClick = async () => { throw new Error('Asynchronous error'); };
*
* <Button onClick={errorWrapper(handleClick)}>Click me</Button>
*/
export function errorWrapper<A extends unknown[]>(
fn: (...args: A) => Promise<void> | void,
): (...args: A) => void {
return (...args: A) => {
try {
const p = fn(...args);
// Check if the function returns a promise to catch async errors
if (p instanceof Promise)
p.catch((error: unknown) => {
console.error('Error thrown asynchronously', error);
});
} catch (error) {
console.error('Error thrown synchronously', error);
}
};
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Kopioin tämän funktion Button.tsx:n sisään. Ymmärsinkö oikein? 😄

Copy link
Owner

@samuliasmala samuliasmala Jan 19, 2025

Choose a reason for hiding this comment

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

Itse asiassa ajattelin että olisi kopioinut tämän funktion utils kansion johonkin tiedostoon, ja käyttänyt sitä Button-tiedostossa. Sitä voi käyttää Buttonin ulkopuolella kuten nyt teet, mutta jos käyttäisit sitä Button-komponentissa niin sitä ei tarvitsisi käyttää joka kerta kun käyttää async-funktiota onClick-handlerissä.

Eli perus-buttonissa onClick-propertyyn ei voi laittaa async-funktiota, mutta jos muuttaisi Button.tsx-tiedostoa seuraavasti niin sitten voisit poistaa errorWrapper funktion esim. index.tsx tiedostosta ja laittaa kaikkiin paikkoihin missä käytät Button-komponenttia async-funktion onClick handleriin.

import { ComponentPropsWithoutRef, MouseEvent } from 'react';
import { twMerge } from 'tailwind-merge';
import { errorWrapper } from '~utils/jokutiedosto';

type ButtonProps = ComponentPropsWithoutRef<'button'> & {
  onClick?: (
    event: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>,
  ) => void | Promise<void>;
};

export function Button({ children, className, onClick, ...rest }: ButtonProps) {
  return (
    <button
      onClick={onClick === undefined ? undefined : errorWrapper(onClick)}
      className={twMerge(
        `mt-6 w-full rounded-md border border-lines bg-primary p-2 text-lg font-medium text-white disabled:bg-gray-300 disabled:text-gray-500`,
        className,
      )}
      {...rest}
    >
      {children}
    </button>
  );
}

Eli kun tekee näin, niin Button komponenttiin voi hyvillä mielin laittaa aina async-funktion eikä errorWrapper komponenttia tarvitse importata joka paikassa.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oliko muuten ComponentPropsWithoutRef<'button'> käytön syynä mitään erityistä? Mietin että olisiko tässä voinut käyttääButtonHTMLAttributes<HTMLButtonElement>?

Copy link
Owner

Choose a reason for hiding this comment

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

Olisi voinut käyttää tuotakin. Suosin tuota käyttämääni siksi, ettei tarvitse muistaa tuota ButtonHTMLAttributes mikä on jokaiselle html-komponentille eri. Ja sitten lisäksi se on vähän lyhyempi. Julkaisin Notion-muistiinpanoni asiasta mitä kirjasin itseäni varten, jos kiinnostaa vilkaista.

export function Button({
children,
className,
Expand Down
15 changes: 10 additions & 5 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { FormEvent, HTMLAttributes, useState } from 'react';
import { Button } from '~/components/Button';
import { Button, errorWrapper } from '~/components/Button';
import { TitleText } from '~/components/TitleText';
import { Input } from '../components/Input';
import { DeleteModal } from '~/components/DeleteModal';
Expand Down Expand Up @@ -168,7 +168,12 @@ function GiftList() {

if (isFetching)
return (
<p className="loading-dots mt-4 text-lg font-bold">Noudetaan lahjoja</p>
<p className="mt-4 text-lg font-bold">
Noudetaan lahjoja{' '}
<span className="absolute ml-2 mt-1.5">
<SvgSpinner width={18} height={18} className="animate-spin" />
</span>
</p>
);

if (error) return <p className="mt-5 bg-red-500 text-lg">{error.message}</p>;
Expand Down Expand Up @@ -270,13 +275,13 @@ function UserDetailModal({
<div className="flex w-full justify-center">
<Button
className="mb-4 ml-3 mr-3 mt-4 flex h-8 w-full max-w-56 items-center justify-center rounded-md bg-primary text-sm font-medium"
onClick={() => {
onClick={errorWrapper(async () => {
try {
void mutateAsync();
await mutateAsync();
} catch (e) {
handleErrorToast(handleError(e));
}
}}
})}
disabled={isPending}
>
{' '}
Expand Down
Loading