Skip to content

Commit

Permalink
Resultify
Browse files Browse the repository at this point in the history
  • Loading branch information
LeonmanRolls committed Oct 28, 2024
1 parent 554e4c7 commit 8caf1e7
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 31 deletions.
4 changes: 2 additions & 2 deletions src/components/@molecules/SearchInput/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ export const SearchInput = ({ size = 'extraLarge' }: { size?: 'medium' | 'extraL
$state={state}
data-testid="search-input-results"
>
{dropdownItems.map((searchItem, index) => (
{/* {dropdownItems.map((searchItem, index) => (
<SearchResult
clickCallback={handleSearch}
hoverCallback={setSelected}
Expand All @@ -742,7 +742,7 @@ export const SearchInput = ({ size = 'extraLarge' }: { size?: 'medium' | 'extraL
}
usingPlaceholder={searchItem.isHistory ? false : usingPlaceholder}
/>
))}
))} */}
</SearchResultsContainer>
)

Expand Down
68 changes: 40 additions & 28 deletions src/pages/legacyfavourites.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable max-classes-per-file */
import { Effect, pipe } from 'effect'
import { Dispatch, ReactElement, SetStateAction, useEffect, useState } from 'react'
import styled, { css } from 'styled-components'
import { match } from 'ts-pattern'
import { useChainId } from 'wagmi'

import { truncateFormat } from '@ensdomains/ensjs/utils'
Expand All @@ -12,8 +12,17 @@ import { Spacer } from '@app/components/@atoms/Spacer'
import { Outlink } from '@app/components/Outlink'
import { Content } from '@app/layouts/Content'
import { ContentGrid } from '@app/layouts/ContentGrid'
import { thread } from '@app/utils/utils'

const { try: EffectTry, flatMap, map, match, runSync, sync } = Effect
type Result<T, E = undefined> = { ok: true; value: T } | { ok: false; error: E | undefined }

const Ok = <T,>(data: T): Result<T, never> => {
return { ok: true, value: data }
}

const Err = <E,>(error?: E): Result<never, E> => {
return { ok: false, error }
}

const Container = styled.div(
({ theme }) => css`
Expand Down Expand Up @@ -59,51 +68,54 @@ type LegacyFavorite = {
}

// eslint-disable-next-line react/no-unused-prop-types
type SimpleFavorite = { name: string; expiry: Date }
type SimpleFavorite = { name: string; expiry: Date | null }

class JsonParseError extends SyntaxError {}

const invalidDateCheck = (favorite: SimpleFavorite) =>
favorite?.expiry?.toString() === 'Invalid Date' ? console.log('Invalid date') : null

export const getLegacyFavorites = (): string =>
globalThis?.localStorage?.getItem('ensFavourites') || '{}'
globalThis?.localStorage?.getItem('ensFavourites') || '[]'

export const simplifyLegacyFavorites = (legacyFavorites: any): SimpleFavorite[] => {
export const simplifyLegacyFavorites = (
legacyFavoritesResult: LegacyFavorite[],
): SimpleFavorite[] => {
const legacyFavorites = legacyFavoritesResult
if (!legacyFavorites?.length) {
return []
}
return legacyFavorites.map((favorite: any) => ({
return legacyFavorites.map((favorite: LegacyFavorite) => ({
name: favorite.name,
expiry: favorite.expiryTime ? new Date(favorite.expiryTime) : null,
}))
}

const jsonParseEffect = (input: string): Effect.Effect<LegacyFavorite[], JsonParseError> =>
EffectTry({
try: () => JSON.parse(input),
catch: (error) => new JsonParseError(error as string),
})

const setFavoritesProgram = (setState: Dispatch<SetStateAction<SimpleFavorite[] | null>>) =>
pipe(
sync(getLegacyFavorites),
flatMap(jsonParseEffect),
map(simplifyLegacyFavorites),
// Easy to 'interrupt' the computation at any point and do stuff
Effect.tap((simpleLegacyFavorites) => simpleLegacyFavorites.map(invalidDateCheck)),
match({
onFailure: console.error,
onSuccess: setState,
}),
)
const jsonParse = (input: string): Result<LegacyFavorite[], JsonParseError> => {
try {
return Ok(JSON.parse(input))
} catch (error) {
return Err(new JsonParseError(error as string))
}
}

export default function Page() {
const [favorites, setFavorites] = useState<SimpleFavorite[] | null>(null)
const chainId = useChainId()

useEffect(() => {
runSync(setFavoritesProgram(setFavorites))
const result: Result<SimpleFavorite[]> = thread(
{},
getLegacyFavorites,
jsonParse,
simplifyLegacyFavorites,
)
match(result)
.with({ ok: true }, ({ value }) => {
setFavorites(value)
})
.with({ ok: false }, ({ error }) => {
console.error(error)
setFavorites([])
})
.exhaustive()
}, [])

return (
Expand Down
30 changes: 29 additions & 1 deletion src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ export const createDateAndValue = <TValue extends bigint | number>(value: TValue
value,
})

type Result<T, E = undefined> = { ok: true; value: T } | { ok: false; error: E | undefined }

const Ok = <T>(data: T): Result<T, never> => {
return { ok: true, value: data }
}

const Err = <E>(error?: E): Result<never, E> => {
return { ok: false, error }
}

/*
Following types are based on this solution: https://stackoverflow.com/questions/53173203/typescript-recursive-function-composition/53175538#53175538
Best to just move on and not try to understand it. (This is copilot's opintion!)
Expand All @@ -204,4 +214,22 @@ type LaxReturnType<F> = F extends (...args: any) => infer R ? R : never
export const thread = <F extends [(arg: any) => any, ...Array<(arg: any) => any>]>(
arg: ArgType<F[0]>,
...f: F & AsChain<F>
): LaxReturnType<Last<F>> => f.reduce((acc, fn) => fn(acc), arg) as LaxReturnType<Last<F>>
): Result<LaxReturnType<Last<F>>, any> => {
try {
const rslt = f.reduce((acc, fn) => {
if (acc && typeof acc === 'object' && 'ok' in acc) {
if (!acc.ok) return acc
return fn(acc.value)
}
return fn(acc)
}, arg)

if (rslt && typeof rslt === 'object' && 'ok' in rslt) {
return rslt
}

return Ok(rslt)
} catch (e) {
return Err(e)
}
}

0 comments on commit 8caf1e7

Please sign in to comment.