Skip to content

Commit

Permalink
Add metacom
Browse files Browse the repository at this point in the history
  • Loading branch information
DemianParkhomenko committed Jan 19, 2024
1 parent 3fbac21 commit 25e000f
Show file tree
Hide file tree
Showing 18 changed files with 254 additions and 40 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_URL_PRODUCT_API=ws://messenger-backend.fly.dev
2 changes: 2 additions & 0 deletions .env.local.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NEXT_PUBLIC_URL_PRODUCT_API=ws://localhost:8000
# NEXT_PUBLIC_URL_PRODUCT_API=ws://messenger-backend.fly.dev
4 changes: 3 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}
const nextConfig = {
reactStrictMode: true,
}

module.exports = nextConfig
78 changes: 75 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
"prettier:check": "prettier --check .",
"prettier:write": "prettier --write .",
"typescript:check": "tsc -p tsconfig.json",
"env:local": "cp .env.local.dist .env.local",
"prepare": "husky install",
"cspell": "cspell --show-suggestions --show-context --gitignore ."
},
"dependencies": {
"metacom": "^3.1.2",
"next": "14.0.3",
"next-themes": "^0.2.1",
"react": "^18",
"react-dom": "^18"
"react-dom": "^18",
"react-hot-toast": "^2.4.1"
},
"devDependencies": {
"@types/node": "^20",
Expand Down
1 change: 1 addition & 0 deletions project-words.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Autobuild
autofetch
GOLUB
tailwindcss
tsbuildinfo
Expand Down
Binary file removed src/app/favicon.ico
Binary file not shown.
18 changes: 9 additions & 9 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import type { Metadata } from 'next'
'use client'

import Providers from '@/store/Providers'
import { FC } from 'react'
import { Toaster } from 'react-hot-toast'

import { text, title } from './fonts'
import './globals.css'

export const metadata: Metadata = {
description: 'Generated by create next app',
title: 'Create Next App',
interface PageProps {
children: React.ReactNode
}

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
const Layout: FC<PageProps> = ({ children } = { children: [] }) => {
return (
<html lang="en" suppressHydrationWarning>
<body className={`${title.variable} ${text.variable}`}>
<Providers>{children}</Providers>
<Toaster position="top-right" />
</body>
</html>
)
}

export default Layout
47 changes: 23 additions & 24 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import IconChange from '@/components/UI/Icons/IconChange'
import Image from 'next/image'
'use client'

import Button from '@/components/UI/Button'
import { useApi, useApiContext } from '@/utils'
import { notify } from '@/utils/notifications'

const Home = () => {
const api = useApiContext()
const condition = true

const { fetch, response: calculated } = useApi(
() => condition && api.example.add({ a: 1, b: 2 }),
{ onSuccess: () => notify('It works') }
)
const { response: data } = useApi(() => condition && api.example.data(), {
autofetch: true,
})

export default function Home() {
return (
<div className="flex items-baseline gap-5">
<div className="flex flex-col items-center">
This is Image:{' '}
<Image
alt="change"
className="fill-blue-500"
height={24}
src="/icons/change.svg"
width={24}
/>
</div>
<div className="flex flex-col items-center">
This is an IconChange component:{' '}
<IconChange
className="text-base-gray-1 hover:text-bright-orange transition-colors"
size="lg"
/>
<p>Hover me!</p>
</div>
<div>GOLUB</div>
<div>🚀</div>
<div className="flex items-center gap-20 text-white">
<Button onClick={fetch}>Calculate 1 + 2</Button>
{calculated}
<div> {data}</div>
</div>
)
}

export default Home
2 changes: 1 addition & 1 deletion src/components/UI/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type ButtonProps = {
children: ReactNode
className?: string
disabled?: boolean
onClick?: () => void
onClick?: () => Promise<void> | void
type?: 'button' | 'reset' | 'submit'
}

Expand Down
1 change: 1 addition & 0 deletions src/constants/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const URL_PRODUCT_API = process.env.NEXT_PUBLIC_URL_PRODUCT_API || ''
1 change: 1 addition & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './env'
11 changes: 10 additions & 1 deletion src/store/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client'

import { ApiContext, useApiLoader } from '@/utils'
import { ThemeProvider } from 'next-themes'
import { FC, ReactNode } from 'react'

Expand All @@ -8,7 +9,15 @@ type ProvidersProps = {
}

const Providers: FC<ProvidersProps> = ({ children }) => {
return <ThemeProvider attribute="class">{children}</ThemeProvider>
const { api, isApiReady } = useApiLoader()

return (
<ThemeProvider attribute="class">
{isApiReady && api && (
<ApiContext.Provider value={api}>{children}</ApiContext.Provider>
)}
</ThemeProvider>
)
}

export default Providers
60 changes: 60 additions & 0 deletions src/utils/api/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useCallback, useEffect, useRef, useState } from 'react'

import { notify } from '..'

export const useApi = <T extends Promise<any>>(
fetcher: () => '' | T | false | null | undefined,
options: {
autofetch?: boolean
onBeforeFetch?: () => Promise<void> | void
onError?: () => void
onResponse?: (res: Awaited<T>) => Promise<void> | void
onSuccess?: () => void
} = {}
) => {
const [isLoading, setLoading] = useState(false)
const [response, setResponse] = useState(null)

const optionsRef = useRef(options)
optionsRef.current = options

const fetcherRef = useRef(fetcher)
fetcherRef.current = fetcher

const refetch = useCallback(async () => {
setLoading(true)
await optionsRef.current.onBeforeFetch?.()
const res = await fetcherRef.current()
if (!res) {
setLoading(false)
return
}
await optionsRef.current.onResponse?.(res)
if (res.error) {
if (optionsRef.current.onError) {
await optionsRef.current.onError?.()
}
} else {
setResponse(res)
try {
await optionsRef.current.onSuccess?.()
} catch (e) {
notify('Network error', { type: 'error' })
console.error(e)
}
}
setLoading(false)
}, [])

useEffect(() => {
if (optionsRef.current.autofetch) {
refetch()
}
}, [refetch])

return {
fetch: refetch,
isLoading,
response,
}
}
2 changes: 2 additions & 0 deletions src/utils/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './metacom'
export * from './hooks'
36 changes: 36 additions & 0 deletions src/utils/api/metacom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { URL_PRODUCT_API } from '@/constants'
import { Metacom } from 'metacom'
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'

const units = ['example']
const metacom = Metacom.create(URL_PRODUCT_API)

export const useApiLoader = () => {
const [api, setApi] = useState<any>({})
const isApiReady = useMemo(
() => Object.keys(api).length === units.length,
[api]
)
const loadApi = useCallback(async () => {
await metacom.load(...units)
setApi(metacom.api)
}, [])

useEffect(() => {
;(async () => {
if (!isApiReady) loadApi()
})()
}, [isApiReady, loadApi])

return { api, isApiReady }
}

export const ApiContext = createContext<any>(null)
export const useApiContext = () => useContext(ApiContext)
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './misc'
export * from './api'
export * from './notifications'
Loading

0 comments on commit 25e000f

Please sign in to comment.