diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e0579324d3..58961fe5bc 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,6 +3,7 @@ + ### Best Way to Test diff --git a/edge-functions/README.md b/edge-functions/README.md index d6afd33707..11cc4495a9 100644 --- a/edge-functions/README.md +++ b/edge-functions/README.md @@ -33,8 +33,3 @@ - [Power Parity Pricing](./power-parity-pricing) - [Query Parameters Filter](./query-params-filter) - [Scalable redirects with Upstash](./redirects-upstash) - - - - - diff --git a/edge-functions/ab-testing-simple/pages/_app.tsx b/edge-functions/ab-testing-simple/pages/_app.tsx index 3a03d362d7..f1f06e869a 100644 --- a/edge-functions/ab-testing-simple/pages/_app.tsx +++ b/edge-functions/ab-testing-simple/pages/_app.tsx @@ -7,7 +7,10 @@ export default function MyApp({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/edge-functions/add-header/README.md b/edge-functions/add-header/README.md index 055a493e9a..6aabba6574 100644 --- a/edge-functions/add-header/README.md +++ b/edge-functions/add-header/README.md @@ -10,10 +10,7 @@ export function middleware() { const response = NextResponse.next() // Set custom header - response.headers.set( - "x-modified-edge", - "true" - ) + response.headers.set('x-modified-edge', 'true') // Return response return response diff --git a/edge-functions/add-header/pages/_app.tsx b/edge-functions/add-header/pages/_app.tsx index 10a18ddae3..f87df8e4a5 100644 --- a/edge-functions/add-header/pages/_app.tsx +++ b/edge-functions/add-header/pages/_app.tsx @@ -9,10 +9,7 @@ function App({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/edge-functions/add-header/pages/_middleware.ts b/edge-functions/add-header/pages/_middleware.ts index e2bd01eda6..42534c15d9 100644 --- a/edge-functions/add-header/pages/_middleware.ts +++ b/edge-functions/add-header/pages/_middleware.ts @@ -5,10 +5,7 @@ export function middleware() { const response = NextResponse.next() // Set custom header - response.headers.set( - "x-modified-edge", - "true" - ) + response.headers.set('x-modified-edge', 'true') // Return response return response diff --git a/edge-functions/add-header/pages/index.tsx b/edge-functions/add-header/pages/index.tsx index 18c6cf696d..c288d4b3bf 100644 --- a/edge-functions/add-header/pages/index.tsx +++ b/edge-functions/add-header/pages/index.tsx @@ -33,7 +33,10 @@ function IndexPage() {
Adding headers at the edge - In some cases we might want to add or modify the headers from an incoming request for different reasons, AB testing, personalization, analytics, etc. To have access to the tenative response we can call NextResponse.next() and then modify its headers: + In some cases we might want to add or modify the headers from an + incoming request for different reasons, AB testing, personalization, + analytics, etc. To have access to the tenative response we can call{' '} + NextResponse.next() and then modify its headers: {`// Store the response so we can modify its headers diff --git a/edge-functions/api-rate-limit-and-tokens/lib/api/keys.ts b/edge-functions/api-rate-limit-and-tokens/lib/api/keys.ts index 800b700c71..5b31463c8a 100644 --- a/edge-functions/api-rate-limit-and-tokens/lib/api/keys.ts +++ b/edge-functions/api-rate-limit-and-tokens/lib/api/keys.ts @@ -35,7 +35,10 @@ export const tokenRateLimit = initRateLimit(async (request) => { let payload: ApiTokenPayload try { - const verified = await jwtVerify(token, new TextEncoder().encode(API_KEYS_JWT_SECRET_KEY)) + const verified = await jwtVerify( + token, + new TextEncoder().encode(API_KEYS_JWT_SECRET_KEY) + ) payload = verified.payload as ApiTokenPayload } catch (err) { return tokenExpired() diff --git a/edge-functions/api-rate-limit-and-tokens/pages/api/keys.ts b/edge-functions/api-rate-limit-and-tokens/pages/api/keys.ts index 74873eebc3..b758eece6e 100644 --- a/edge-functions/api-rate-limit-and-tokens/pages/api/keys.ts +++ b/edge-functions/api-rate-limit-and-tokens/pages/api/keys.ts @@ -5,7 +5,8 @@ import { API_KEYS, API_KEYS_JWT_SECRET_KEY } from '@lib/api/constants' import type { ApiTokenPayload } from '@lib/api/keys' import { upstashRest } from '@lib/upstash' -const decode = (jwt: string) => JSON.parse(new TextDecoder().decode(base64url.decode(jwt.split('.')[1]))) +const decode = (jwt: string) => + JSON.parse(new TextDecoder().decode(base64url.decode(jwt.split('.')[1]))) export default async function keys(req: NextApiRequest, res: NextApiResponse) { try { diff --git a/edge-functions/basic-auth-password/pages/_app.tsx b/edge-functions/basic-auth-password/pages/_app.tsx index 00c95ab1c2..480e8ed6db 100644 --- a/edge-functions/basic-auth-password/pages/_app.tsx +++ b/edge-functions/basic-auth-password/pages/_app.tsx @@ -7,7 +7,10 @@ export default function MyApp({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/edge-functions/bot-protection-botd/next.config.js b/edge-functions/bot-protection-botd/next.config.js index a8290cfee0..2f17a058ad 100644 --- a/edge-functions/bot-protection-botd/next.config.js +++ b/edge-functions/bot-protection-botd/next.config.js @@ -1,9 +1,6 @@ -const withTM = require('next-transpile-modules')( - ['@vercel/examples-ui'], - { - resolveSymlinks: false, - } -) +const withTM = require('next-transpile-modules')(['@vercel/examples-ui'], { + resolveSymlinks: false, +}) module.exports = withTM({ typescript: { diff --git a/edge-functions/clerk-authentication/components/CTASection.jsx b/edge-functions/clerk-authentication/components/CTASection.jsx index 8830da6b46..7946a14809 100644 --- a/edge-functions/clerk-authentication/components/CTASection.jsx +++ b/edge-functions/clerk-authentication/components/CTASection.jsx @@ -1,28 +1,28 @@ export function CTASection() { return ( -
-
-

- Ready for authentication at the edge? +
+
+

+ Ready for authentication at the edge?

-

+

Stateless, revocable authentication is included in every Clerk plan.

-
- ); + ) } diff --git a/edge-functions/clerk-authentication/components/HeadTags.jsx b/edge-functions/clerk-authentication/components/HeadTags.jsx index f787cd6e16..311490e632 100644 --- a/edge-functions/clerk-authentication/components/HeadTags.jsx +++ b/edge-functions/clerk-authentication/components/HeadTags.jsx @@ -1,41 +1,41 @@ -import Head from 'next/head'; +import Head from 'next/head' export function HeadTags() { - const title = 'Demo: Next.js authentication at the edge with Clerk'; + const title = 'Demo: Next.js authentication at the edge with Clerk' const desc = - 'Try an interactive demo of authentication at the edge with Clerk and Next.js'; - const canonical = 'https://edge.clerk.app'; + 'Try an interactive demo of authentication at the edge with Clerk and Next.js' + const canonical = 'https://edge.clerk.app' return ( {title} - + - - + + - - - - + + + + - - + + - + - - - - - + + + + + - ); + ) } diff --git a/edge-functions/clerk-authentication/components/Layout.jsx b/edge-functions/clerk-authentication/components/Layout.jsx index 6a97ff2a37..e290e8501c 100644 --- a/edge-functions/clerk-authentication/components/Layout.jsx +++ b/edge-functions/clerk-authentication/components/Layout.jsx @@ -1,3 +1,3 @@ export const Layout = ({ children }) => { - return
{children}
; -}; + return
{children}
+} diff --git a/edge-functions/clerk-authentication/components/index.js b/edge-functions/clerk-authentication/components/index.js index 6f1412ac02..b5ca4deb68 100644 --- a/edge-functions/clerk-authentication/components/index.js +++ b/edge-functions/clerk-authentication/components/index.js @@ -1,8 +1,8 @@ -export * from './Layout'; -export * from './HeadTags'; -export * from './HeroSection'; -export * from './CTASection'; -export * from './Pattern'; -export * from './statelessDoneRightSection'; -export * from './tryRenovationSection'; -export * from './twoStrategiesSection'; +export * from './Layout' +export * from './HeadTags' +export * from './HeroSection' +export * from './CTASection' +export * from './Pattern' +export * from './statelessDoneRightSection' +export * from './tryRenovationSection' +export * from './twoStrategiesSection' diff --git a/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTDemo.jsx b/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTDemo.jsx index 7a5729a2ed..b90c0e9f2a 100644 --- a/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTDemo.jsx +++ b/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTDemo.jsx @@ -1,68 +1,68 @@ -import React from 'react'; -import { useSession } from '@clerk/nextjs'; -import { Navigation, Pagination } from 'swiper'; -import { Swiper, SwiperSlide } from 'swiper/react'; -import { TokenCard } from './TokenCard'; -import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid'; +import React from 'react' +import { useSession } from '@clerk/nextjs' +import { Navigation, Pagination } from 'swiper' +import { Swiper, SwiperSlide } from 'swiper/react' +import { TokenCard } from './TokenCard' +import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/solid' function useInterval(callback, delay) { - const savedCallback = React.useRef(callback); + const savedCallback = React.useRef(callback) React.useLayoutEffect(() => { - savedCallback.current = callback; - }, [callback]); + savedCallback.current = callback + }, [callback]) React.useEffect(() => { if (!delay) { - return; + return } - const id = setInterval(() => savedCallback.current(), delay); - return () => clearInterval(id); - }, [delay]); + const id = setInterval(() => savedCallback.current(), delay) + return () => clearInterval(id) + }, [delay]) } export const JWTDemo = () => { - const session = useSession(); - const [swiperRef, setSwiperRef] = React.useState(null); - const [tokens, setTokens] = React.useState([]); + const session = useSession() + const [swiperRef, setSwiperRef] = React.useState(null) + const [tokens, setTokens] = React.useState([]) const prependAndSlideToStart = React.useCallback(() => { if (!swiperRef) { - return; + return } - swiperRef.slideTo(1, 0); - swiperRef.update(); - swiperRef.slideTo(0); - }, [swiperRef]); + swiperRef.slideTo(1, 0) + swiperRef.update() + swiperRef.slideTo(0) + }, [swiperRef]) const getToken = React.useCallback(async () => { try { - const token = await session.getToken(); + const token = await session.getToken() if (tokens[0] !== token) { - setTokens([token, ...tokens]); - prependAndSlideToStart(); + setTokens([token, ...tokens]) + prependAndSlideToStart() } } catch (e) { - console.log('JWTDemo::getToken error', e); + console.log('JWTDemo::getToken error', e) } - }, [session, tokens, prependAndSlideToStart]); + }, [session, tokens, prependAndSlideToStart]) React.useEffect(() => { - getToken(); - }, [getToken]); + getToken() + }, [getToken]) useInterval(async () => { - void getToken(); - }, 1000); + void getToken() + }, 1000) - const tokenCount = tokens.length; + const tokenCount = tokens.length const generatedTokensText = `${tokenCount} ${ tokenCount === 1 ? 'JWT' : 'JWTs' - } generated since page load`; + } generated since page load` return ( <> -
+
{ ))}
-
+
{generatedTokensText}
- ); -}; + ) +} diff --git a/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTMock.jsx b/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTMock.jsx index 809d1a0600..200c4ce62d 100644 --- a/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTMock.jsx +++ b/edge-functions/clerk-authentication/components/statelessDoneRightSection/JWTMock.jsx @@ -1,34 +1,34 @@ -import { SignInCover } from 'utils/buttons'; -import React from 'react'; +import { SignInCover } from 'utils/buttons' +import React from 'react' export const JWTMock = () => { return ( -
-
-
-
-
-
-

+
+
+
+
+
+
+

JWT #1

-
-
+
+
-
Issued At
-
+
Issued At
+
{new Date().toLocaleString()}
-
+
Expires In
{
- Sign in to see JWT demo + Sign in to see JWT demo
- ); -}; + ) +} diff --git a/edge-functions/clerk-authentication/components/statelessDoneRightSection/StatelessDoneRightSection.jsx b/edge-functions/clerk-authentication/components/statelessDoneRightSection/StatelessDoneRightSection.jsx index 4dd0033b16..c410909f03 100644 --- a/edge-functions/clerk-authentication/components/statelessDoneRightSection/StatelessDoneRightSection.jsx +++ b/edge-functions/clerk-authentication/components/statelessDoneRightSection/StatelessDoneRightSection.jsx @@ -1,47 +1,47 @@ -import React from 'react'; -import { SignedIn, SignedOut } from '@clerk/nextjs'; -import { LeftPattern } from 'utils/patterns'; +import React from 'react' +import { SignedIn, SignedOut } from '@clerk/nextjs' +import { LeftPattern } from 'utils/patterns' -import { JWTDemo } from './JWTDemo'; -import { JWTMock } from './JWTMock'; +import { JWTDemo } from './JWTDemo' +import { JWTMock } from './JWTMock' export function StatelessDoneRightSection() { return ( -
-
+
+
-
-
-

+
+
+

Stateless done right

-

+

Short-lived, automatically-refreshing JWTs provide simple, robust security

-
-
-
-
+
+
+
+

Short-lived

-

+

Each JWT only lasts 60 seconds. If a session needs to be revoked, this short lifetime ensures attackers will be stopped within 60 seconds.

-
-
+
+

Automatically-refreshing

-

+

Clerk's Next.js SDK automatically refreshes tokens before they expire, so there's no extra work for developers. Watch it in real - time below. @@ -58,5 +58,5 @@ export function StatelessDoneRightSection() {

- ); + ) } diff --git a/edge-functions/clerk-authentication/components/statelessDoneRightSection/TokenCard.jsx b/edge-functions/clerk-authentication/components/statelessDoneRightSection/TokenCard.jsx index a7ce52f085..91cefe66e3 100644 --- a/edge-functions/clerk-authentication/components/statelessDoneRightSection/TokenCard.jsx +++ b/edge-functions/clerk-authentication/components/statelessDoneRightSection/TokenCard.jsx @@ -1,10 +1,10 @@ -import React from 'react'; -import { useForceRender } from 'utils/forceRender'; -import { parseClaims, parseToken } from 'utils/token'; +import React from 'react' +import { useForceRender } from 'utils/forceRender' +import { parseClaims, parseToken } from 'utils/token' // We must hardcode the classnames // otherwise they will be purged by purgeCss during prod build -const getBarColorForPercentage = p => { +const getBarColorForPercentage = (p) => { return p < 50 ? 'bg-green-500' : p < 60 @@ -15,10 +15,10 @@ const getBarColorForPercentage = p => { ? 'bg-yellow-500' : p < 90 ? 'bg-yellow-600' - : 'bg-red-600'; -}; + : 'bg-red-600' +} -const getTextColorForPercentage = p => { +const getTextColorForPercentage = (p) => { return p < 50 ? 'text-green-500' : p < 60 @@ -29,34 +29,34 @@ const getTextColorForPercentage = p => { ? 'text-yellow-500' : p < 90 ? 'text-yellow-600' - : 'text-red-600'; -}; + : 'text-red-600' +} -const useForceRenderWhileValid = ttl => { - const { stop } = useForceRender(); +const useForceRenderWhileValid = (ttl) => { + const { stop } = useForceRender() if (ttl === 0) { - stop(); + stop() } -}; +} export const TokenCard = ({ token, index, total }) => { const { totalValidForSec, timeToLiveInSec, issuedAt } = parseClaims( - parseToken(token), - ); - useForceRenderWhileValid(timeToLiveInSec); - const percentGone = 100 - (100 * timeToLiveInSec) / totalValidForSec; + parseToken(token) + ) + useForceRenderWhileValid(timeToLiveInSec) + const percentGone = 100 - (100 * timeToLiveInSec) / totalValidForSec - const barColor = getBarColorForPercentage(percentGone); - const textColor = getTextColorForPercentage(percentGone); + const barColor = getBarColorForPercentage(percentGone) + const textColor = getTextColorForPercentage(percentGone) return ( -
-
-
-

+
+
+
+

JWT #{total - index}{' '} {index === 0 && ( - + Currently active )} @@ -66,16 +66,16 @@ export const TokenCard = ({ token, index, total }) => { className={`h-1 transition-all ease-linear duration-1000 ${barColor}`} style={{ width: `${percentGone}%` }} /> -
-
+
+
-
Issued At
-
+
Issued At
+
{new Date(issuedAt * 1000).toLocaleString()}
-
+
Expires In
{
- ); -}; + ) +} diff --git a/edge-functions/clerk-authentication/components/statelessDoneRightSection/index.js b/edge-functions/clerk-authentication/components/statelessDoneRightSection/index.js index 708fba5bcc..c0f2350187 100644 --- a/edge-functions/clerk-authentication/components/statelessDoneRightSection/index.js +++ b/edge-functions/clerk-authentication/components/statelessDoneRightSection/index.js @@ -1 +1 @@ -export * from './StatelessDoneRightSection'; +export * from './StatelessDoneRightSection' diff --git a/edge-functions/clerk-authentication/components/tryRenovationSection/TryRenovationSection.jsx b/edge-functions/clerk-authentication/components/tryRenovationSection/TryRenovationSection.jsx index 6b67e66004..8df7b6ca91 100644 --- a/edge-functions/clerk-authentication/components/tryRenovationSection/TryRenovationSection.jsx +++ b/edge-functions/clerk-authentication/components/tryRenovationSection/TryRenovationSection.jsx @@ -1,27 +1,27 @@ -import React from 'react'; -import { SignedIn, SignedOut } from '@clerk/nextjs'; -import { LeftPattern } from 'utils/patterns'; +import React from 'react' +import { SignedIn, SignedOut } from '@clerk/nextjs' +import { LeftPattern } from 'utils/patterns' -import { SessionList } from './SessionList'; -import { SessionMock } from './SessionMock'; +import { SessionList } from './SessionList' +import { SessionMock } from './SessionMock' export function TryRenovationSection() { return ( -
-
+
+
-
-
-

+
+
+

Try revocation

-

+

Sign in on two devices to test revocation

-
-
+
+
@@ -33,5 +33,5 @@ export function TryRenovationSection() {
- ); + ) } diff --git a/edge-functions/clerk-authentication/components/tryRenovationSection/index.js b/edge-functions/clerk-authentication/components/tryRenovationSection/index.js index 1c0b167f9d..3eea39fba2 100644 --- a/edge-functions/clerk-authentication/components/tryRenovationSection/index.js +++ b/edge-functions/clerk-authentication/components/tryRenovationSection/index.js @@ -1 +1 @@ -export * from './TryRenovationSection'; +export * from './TryRenovationSection' diff --git a/edge-functions/clerk-authentication/components/twoStrategiesSection/TwoStrategiesSection.jsx b/edge-functions/clerk-authentication/components/twoStrategiesSection/TwoStrategiesSection.jsx index 40e29e60db..32aa839d94 100644 --- a/edge-functions/clerk-authentication/components/twoStrategiesSection/TwoStrategiesSection.jsx +++ b/edge-functions/clerk-authentication/components/twoStrategiesSection/TwoStrategiesSection.jsx @@ -1,28 +1,28 @@ -import React from 'react'; -import { LeftPattern } from 'utils/patterns'; +import React from 'react' +import { LeftPattern } from 'utils/patterns' -import { Requester } from './Requester'; +import { Requester } from './Requester' export function TwoStrategiesSection() { // On mobile, stateful will start as hidden - const [visible, setVisible] = React.useState('stateless'); + const [visible, setVisible] = React.useState('stateless') return ( -
-
+
+
-
-
-

+
+
+

Two strategies

-

+

Clerk supports both stateless and stateful authentication at the edge

-
-
- ); + ) } diff --git a/edge-functions/clerk-authentication/components/twoStrategiesSection/index.js b/edge-functions/clerk-authentication/components/twoStrategiesSection/index.js index ba778a6aa3..017954210a 100644 --- a/edge-functions/clerk-authentication/components/twoStrategiesSection/index.js +++ b/edge-functions/clerk-authentication/components/twoStrategiesSection/index.js @@ -1 +1 @@ -export * from './TwoStrategiesSection'; +export * from './TwoStrategiesSection' diff --git a/edge-functions/clerk-authentication/jsconfig.json b/edge-functions/clerk-authentication/jsconfig.json index 528d49f609..a693adcf96 100644 --- a/edge-functions/clerk-authentication/jsconfig.json +++ b/edge-functions/clerk-authentication/jsconfig.json @@ -2,12 +2,8 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "components/*": [ - "components/*" - ], - "utils/*": [ - "utils/*" - ] + "components/*": ["components/*"], + "utils/*": ["utils/*"] } } } diff --git a/edge-functions/clerk-authentication/pages/_app.js b/edge-functions/clerk-authentication/pages/_app.js index 18d3dc1a88..675f129b08 100644 --- a/edge-functions/clerk-authentication/pages/_app.js +++ b/edge-functions/clerk-authentication/pages/_app.js @@ -1,15 +1,15 @@ -import '../styles/globals.css'; -import 'swiper/css'; -import 'swiper/css/pagination'; -import 'swiper/css/navigation'; -import { ClerkProvider } from '@clerk/nextjs'; +import '../styles/globals.css' +import 'swiper/css' +import 'swiper/css/pagination' +import 'swiper/css/navigation' +import { ClerkProvider } from '@clerk/nextjs' function MyApp({ Component, pageProps }) { return ( - ); + ) } -export default MyApp; +export default MyApp diff --git a/edge-functions/clerk-authentication/pages/api/stateful/_middleware.js b/edge-functions/clerk-authentication/pages/api/stateful/_middleware.js index 770b69a644..befdd8b12a 100644 --- a/edge-functions/clerk-authentication/pages/api/stateful/_middleware.js +++ b/edge-functions/clerk-authentication/pages/api/stateful/_middleware.js @@ -1,18 +1,18 @@ -import { requireSession } from '@clerk/nextjs/edge'; -import { withTimer, endTimer, timerResult } from '../../../utils/timer'; +import { requireSession } from '@clerk/nextjs/edge' +import { withTimer, endTimer, timerResult } from '../../../utils/timer' // The handler should return a Response object -const handler = async req => { +const handler = async (req) => { // The session is already verified, but we want // to double-check with Clerk's API to ensure // it hasn't been revoked in the last minute try { - const reverify = await req.session.verifyWithNetwork(); + const reverify = await req.session.verifyWithNetwork() } catch (error) { - return new Response('Forbidden', { status: 403 }); + return new Response('Forbidden', { status: 403 }) } - endTimer(req); + endTimer(req) return new Response( JSON.stringify({ @@ -24,8 +24,8 @@ const handler = async req => { headers: { 'Content-Type': 'application/json', }, - }, - ); -}; + } + ) +} -export default withTimer(requireSession(handler)); +export default withTimer(requireSession(handler)) diff --git a/edge-functions/clerk-authentication/pages/api/stateless/_middleware.js b/edge-functions/clerk-authentication/pages/api/stateless/_middleware.js index e355de1f4b..f68b53ba90 100644 --- a/edge-functions/clerk-authentication/pages/api/stateless/_middleware.js +++ b/edge-functions/clerk-authentication/pages/api/stateless/_middleware.js @@ -1,9 +1,9 @@ -import { requireSession } from '@clerk/nextjs/edge'; -import { withTimer, endTimer, timerResult } from '../../../utils/timer'; +import { requireSession } from '@clerk/nextjs/edge' +import { withTimer, endTimer, timerResult } from '../../../utils/timer' // The handler should return a Response object -const handler = async req => { - endTimer(req); +const handler = async (req) => { + endTimer(req) return new Response( JSON.stringify({ @@ -15,8 +15,8 @@ const handler = async req => { headers: { 'Content-Type': 'application/json', }, - }, - ); -}; + } + ) +} -export default withTimer(requireSession(handler)); +export default withTimer(requireSession(handler)) diff --git a/edge-functions/clerk-authentication/pages/index.js b/edge-functions/clerk-authentication/pages/index.js index 0a29ece498..9c0bfa75bf 100644 --- a/edge-functions/clerk-authentication/pages/index.js +++ b/edge-functions/clerk-authentication/pages/index.js @@ -6,7 +6,7 @@ import { TryRenovationSection, TwoStrategiesSection, CTASection, -} from 'components'; +} from 'components' export default function Home() { return ( @@ -18,5 +18,5 @@ export default function Home() { - ); + ) } diff --git a/edge-functions/clerk-authentication/utils/forceRender.jsx b/edge-functions/clerk-authentication/utils/forceRender.jsx index 51ff425fb8..ba400e228c 100644 --- a/edge-functions/clerk-authentication/utils/forceRender.jsx +++ b/edge-functions/clerk-authentication/utils/forceRender.jsx @@ -1,20 +1,20 @@ -import React from 'react'; +import React from 'react' export const useForceRender = (delay = 1000) => { - const [s, ss] = React.useState(0); - const intervalIdRef = React.useRef(null); + const [s, ss] = React.useState(0) + const intervalIdRef = React.useRef(null) const stop = () => { - const id = intervalIdRef.current; + const id = intervalIdRef.current if (id !== null) { - clearInterval(id); + clearInterval(id) } - }; + } React.useEffect(() => { - intervalIdRef.current = setInterval(() => ss(state => state + 1), delay); - return stop; - }, []); + intervalIdRef.current = setInterval(() => ss((state) => state + 1), delay) + return stop + }, []) - return { stop }; -}; + return { stop } +} diff --git a/edge-functions/clerk-authentication/utils/timer.js b/edge-functions/clerk-authentication/utils/timer.js index 51a577d474..125a2f2d9e 100644 --- a/edge-functions/clerk-authentication/utils/timer.js +++ b/edge-functions/clerk-authentication/utils/timer.js @@ -1,17 +1,17 @@ // Utilities to measure the authentication strategies -export const withTimer = next => { - return req => { - req.startTime = new Date().getTime(); - return next(req); - }; -}; +export const withTimer = (next) => { + return (req) => { + req.startTime = new Date().getTime() + return next(req) + } +} -export const endTimer = req => { - req.endTime = new Date().getTime(); -}; +export const endTimer = (req) => { + req.endTime = new Date().getTime() +} -export const timerResult = req => { +export const timerResult = (req) => { return { authenticationTime: req.endTime - req.startTime, - }; -}; + } +} diff --git a/edge-functions/clerk-authentication/utils/token.js b/edge-functions/clerk-authentication/utils/token.js index cb1dd4f3f3..fce9c21f92 100644 --- a/edge-functions/clerk-authentication/utils/token.js +++ b/edge-functions/clerk-authentication/utils/token.js @@ -1,12 +1,12 @@ -export const parseToken = token => { - return JSON.parse(atob(token.split('.')[1])); -}; +export const parseToken = (token) => { + return JSON.parse(atob(token.split('.')[1])) +} -export const parseClaims = claims => { - const now = Math.round(Date.now() / 1000); - const issuedAt = claims.iat; - const expiresAt = claims.exp; - const totalValidForSec = expiresAt - issuedAt; - const timeToLiveInSec = Math.max(expiresAt - now, 0); - return { issuedAt, expiresAt, totalValidForSec, timeToLiveInSec, now }; -}; +export const parseClaims = (claims) => { + const now = Math.round(Date.now() / 1000) + const issuedAt = claims.iat + const expiresAt = claims.exp + const totalValidForSec = expiresAt - issuedAt + const timeToLiveInSec = Math.max(expiresAt - now, 0) + return { issuedAt, expiresAt, totalValidForSec, timeToLiveInSec, now } +} diff --git a/edge-functions/clerk-authentication/utils/vercelRegion.js b/edge-functions/clerk-authentication/utils/vercelRegion.js index a4f238bed6..871c1b2aa5 100644 --- a/edge-functions/clerk-authentication/utils/vercelRegion.js +++ b/edge-functions/clerk-authentication/utils/vercelRegion.js @@ -1,43 +1,43 @@ const vercelRegions = { - dev1: "Development", - arn1: "Stockholm, Sweden", - bom1: "Mumbai, India", - cdg1: "Paris, France", - cle1: "Cleveland, USA", - dub1: "Dublin, Ireland", - fra1: "Frankfurt, Germany", - gru1: "São Paulo, Brazil", - hkg1: "Hong Kong", - hnd1: "Tokyo, Japan", - iad1: "Washington DC, USA", - icn1: "Seoul, South Korea", - lhr1: "London, UK", - pdx1: "Portland, USA", - sfo1: "San Francisco, USA", - sin1: "Singapore", - syd1: "Sydney, Australia", -}; + dev1: 'Development', + arn1: 'Stockholm, Sweden', + bom1: 'Mumbai, India', + cdg1: 'Paris, France', + cle1: 'Cleveland, USA', + dub1: 'Dublin, Ireland', + fra1: 'Frankfurt, Germany', + gru1: 'São Paulo, Brazil', + hkg1: 'Hong Kong', + hnd1: 'Tokyo, Japan', + iad1: 'Washington DC, USA', + icn1: 'Seoul, South Korea', + lhr1: 'London, UK', + pdx1: 'Portland, USA', + sfo1: 'San Francisco, USA', + sin1: 'Singapore', + syd1: 'Sydney, Australia', +} // Warning: This will mistakenly return "Development" // if not deploying on Vercel export const getVercelRegion = (header) => { - if (!header || header === "") { - return "Development"; + if (!header || header === '') { + return 'Development' } - let regionKey = ""; + let regionKey = '' try { regionKey = header - .split(":") - .filter((x) => x !== "") - .slice(-2)[0]; + .split(':') + .filter((x) => x !== '') + .slice(-2)[0] } catch { - return "Unknown"; + return 'Unknown' } if (regionKey in vercelRegions) { - return vercelRegions[regionKey]; + return vercelRegions[regionKey] } else { - return regionKey; + return regionKey } -}; +} diff --git a/edge-functions/cookies/pages/beta.tsx b/edge-functions/cookies/pages/beta.tsx index af9d49dcd9..0da579dfb6 100644 --- a/edge-functions/cookies/pages/beta.tsx +++ b/edge-functions/cookies/pages/beta.tsx @@ -15,13 +15,8 @@ export default function Beta() { Cookies example - - You are currently in beta! - - diff --git a/edge-functions/cookies/pages/non-beta.tsx b/edge-functions/cookies/pages/non-beta.tsx index fa36f90415..93c010d0be 100644 --- a/edge-functions/cookies/pages/non-beta.tsx +++ b/edge-functions/cookies/pages/non-beta.tsx @@ -15,13 +15,8 @@ export default function NonBeta() { Cookies example - - You are currently not in beta! - - diff --git a/edge-functions/feature-flag-posthog/pages/index.tsx b/edge-functions/feature-flag-posthog/pages/index.tsx index 77029eaab4..9543055459 100644 --- a/edge-functions/feature-flag-posthog/pages/index.tsx +++ b/edge-functions/feature-flag-posthog/pages/index.tsx @@ -1,14 +1,7 @@ import { FEATURE_FLAGS } from '@lib/constants' import { getPostHogInstance } from '@lib/posthog' import { getFeatureFlagVariant } from '@lib/posthog-node' -import { - Layout, - Page, - Text, - List, - Link, - Button, -} from '@vercel/examples-ui' +import { Layout, Page, Text, List, Link, Button } from '@vercel/examples-ui' import Cookies from 'js-cookie' import { useEffect, useState } from 'react' diff --git a/edge-functions/feature-flag-split/pages/index.tsx b/edge-functions/feature-flag-split/pages/index.tsx index 5000e97395..0f6ab8e683 100644 --- a/edge-functions/feature-flag-split/pages/index.tsx +++ b/edge-functions/feature-flag-split/pages/index.tsx @@ -1,12 +1,5 @@ import Cookies from 'js-cookie' -import { - Layout, - Page, - Text, - List, - Link, - Button, -} from '@vercel/examples-ui' +import { Layout, Page, Text, List, Link, Button } from '@vercel/examples-ui' import { SPLITS } from '@lib/split' export default function Index() { diff --git a/edge-functions/geolocation/lib/countries.json b/edge-functions/geolocation/lib/countries.json index 07b2900cbe..98e3adb97b 100644 --- a/edge-functions/geolocation/lib/countries.json +++ b/edge-functions/geolocation/lib/countries.json @@ -1 +1,1709 @@ -[{"cca2":"AW","currencies":{"AWG":{"name":"Aruban florin","symbol":"ƒ"}},"languages":{"nld":"Dutch","pap":"Papiamento"},"flag":"🇦🇼"},{"cca2":"AF","currencies":{"AFN":{"name":"Afghan afghani","symbol":"؋"}},"languages":{"prs":"Dari","pus":"Pashto","tuk":"Turkmen"},"flag":"🇦🇫"},{"cca2":"AO","currencies":{"AOA":{"name":"Angolan kwanza","symbol":"Kz"}},"languages":{"por":"Portuguese"},"flag":"🇦🇴"},{"cca2":"AI","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇦🇮"},{"cca2":"AX","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"swe":"Swedish"},"flag":"🇦🇽"},{"cca2":"AL","currencies":{"ALL":{"name":"Albanian lek","symbol":"L"}},"languages":{"sqi":"Albanian"},"flag":"🇦🇱"},{"cca2":"AD","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"cat":"Catalan"},"flag":"🇦🇩"},{"cca2":"AE","currencies":{"AED":{"name":"United Arab Emirates dirham","symbol":"د.إ"}},"languages":{"ara":"Arabic"},"flag":"🇦🇪"},{"cca2":"AR","currencies":{"ARS":{"name":"Argentine peso","symbol":"$"}},"languages":{"grn":"Guaraní","spa":"Spanish"},"flag":"🇦🇷"},{"cca2":"AM","currencies":{"AMD":{"name":"Armenian dram","symbol":"֏"}},"languages":{"hye":"Armenian"},"flag":"🇦🇲"},{"cca2":"AS","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English","smo":"Samoan"},"flag":"🇦🇸"},{"cca2":"AQ","currencies":[],"languages":{},"flag":"🇦🇶"},{"cca2":"TF","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇹🇫"},{"cca2":"AG","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇦🇬"},{"cca2":"AU","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇦🇺"},{"cca2":"AT","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"bar":"Austro-Bavarian German"},"flag":"🇦🇹"},{"cca2":"AZ","currencies":{"AZN":{"name":"Azerbaijani manat","symbol":"₼"}},"languages":{"aze":"Azerbaijani","rus":"Russian"},"flag":"🇦🇿"},{"cca2":"BI","currencies":{"BIF":{"name":"Burundian franc","symbol":"Fr"}},"languages":{"fra":"French","run":"Kirundi"},"flag":"🇧🇮"},{"cca2":"BE","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"deu":"German","fra":"French","nld":"Dutch"},"flag":"🇧🇪"},{"cca2":"BJ","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇧🇯"},{"cca2":"BF","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇧🇫"},{"cca2":"BD","currencies":{"BDT":{"name":"Bangladeshi taka","symbol":"৳"}},"languages":{"ben":"Bengali"},"flag":"🇧🇩"},{"cca2":"BG","currencies":{"BGN":{"name":"Bulgarian lev","symbol":"лв"}},"languages":{"bul":"Bulgarian"},"flag":"🇧🇬"},{"cca2":"BH","currencies":{"BHD":{"name":"Bahraini dinar","symbol":".د.ب"}},"languages":{"ara":"Arabic"},"flag":"🇧🇭"},{"cca2":"BS","currencies":{"BSD":{"name":"Bahamian dollar","symbol":"$"},"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇧🇸"},{"cca2":"BA","currencies":{"BAM":{"name":"Bosnia and Herzegovina convertible mark","symbol":""}},"languages":{"bos":"Bosnian","hrv":"Croatian","srp":"Serbian"},"flag":"🇧🇦"},{"cca2":"BL","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇧🇱"},{"cca2":"SH","currencies":{"GBP":{"name":"Pound sterling","symbol":"£"},"SHP":{"name":"Saint Helena pound","symbol":"£"}},"languages":{"eng":"English"},"flag":"🇸🇭"},{"cca2":"BY","currencies":{"BYN":{"name":"Belarusian ruble","symbol":"Br"}},"languages":{"bel":"Belarusian","rus":"Russian"},"flag":"🇧🇾"},{"cca2":"BZ","currencies":{"BZD":{"name":"Belize dollar","symbol":"$"}},"languages":{"bjz":"Belizean Creole","eng":"English","spa":"Spanish"},"flag":"🇧🇿"},{"cca2":"BM","currencies":{"BMD":{"name":"Bermudian dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇧🇲"},{"cca2":"BO","currencies":{"BOB":{"name":"Bolivian boliviano","symbol":"Bs."}},"languages":{"aym":"Aymara","grn":"Guaraní","que":"Quechua","spa":"Spanish"},"flag":"🇧🇴"},{"cca2":"BQ","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English","nld":"Dutch","pap":"Papiamento"},"flag":""},{"cca2":"BR","currencies":{"BRL":{"name":"Brazilian real","symbol":"R$"}},"languages":{"por":"Portuguese"},"flag":"🇧🇷"},{"cca2":"BB","currencies":{"BBD":{"name":"Barbadian dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇧🇧"},{"cca2":"BN","currencies":{"BND":{"name":"Brunei dollar","symbol":"$"},"SGD":{"name":"Singapore dollar","symbol":"$"}},"languages":{"msa":"Malay"},"flag":"🇧🇳"},{"cca2":"BT","currencies":{"BTN":{"name":"Bhutanese ngultrum","symbol":"Nu."},"INR":{"name":"Indian rupee","symbol":"₹"}},"languages":{"dzo":"Dzongkha"},"flag":"🇧🇹"},{"cca2":"BV","currencies":[],"languages":{"nor":"Norwegian"},"flag":"🇧🇻"},{"cca2":"BW","currencies":{"BWP":{"name":"Botswana pula","symbol":"P"}},"languages":{"eng":"English","tsn":"Tswana"},"flag":"🇧🇼"},{"cca2":"CF","currencies":{"XAF":{"name":"Central African CFA franc","symbol":"Fr"}},"languages":{"fra":"French","sag":"Sango"},"flag":"🇨🇫"},{"cca2":"CA","currencies":{"CAD":{"name":"Canadian dollar","symbol":"$"}},"languages":{"eng":"English","fra":"French"},"flag":"🇨🇦"},{"cca2":"CC","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇨🇨"},{"cca2":"CH","currencies":{"CHF":{"name":"Swiss franc","symbol":"Fr."}},"languages":{"fra":"French","gsw":"Swiss German","ita":"Italian","roh":"Romansh"},"flag":"🇨🇭"},{"cca2":"CL","currencies":{"CLP":{"name":"Chilean peso","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇨🇱"},{"cca2":"CN","currencies":{"CNY":{"name":"Chinese yuan","symbol":"¥"}},"languages":{"zho":"Chinese"},"flag":"🇨🇳"},{"cca2":"CI","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇨🇮"},{"cca2":"CM","currencies":{"XAF":{"name":"Central African CFA franc","symbol":"Fr"}},"languages":{"eng":"English","fra":"French"},"flag":"🇨🇲"},{"cca2":"CD","currencies":{"CDF":{"name":"Congolese franc","symbol":"FC"}},"languages":{"fra":"French","kon":"Kikongo","lin":"Lingala","lua":"Tshiluba","swa":"Swahili"},"flag":"🇨🇩"},{"cca2":"CG","currencies":{"XAF":{"name":"Central African CFA franc","symbol":"Fr"}},"languages":{"fra":"French","kon":"Kikongo","lin":"Lingala"},"flag":"🇨🇬"},{"cca2":"CK","currencies":{"CKD":{"name":"Cook Islands dollar","symbol":"$"},"NZD":{"name":"New Zealand dollar","symbol":"$"}},"languages":{"eng":"English","rar":"Cook Islands Māori"},"flag":"🇨🇰"},{"cca2":"CO","currencies":{"COP":{"name":"Colombian peso","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇨🇴"},{"cca2":"KM","currencies":{"KMF":{"name":"Comorian franc","symbol":"Fr"}},"languages":{"ara":"Arabic","fra":"French","zdj":"Comorian"},"flag":"🇰🇲"},{"cca2":"CV","currencies":{"CVE":{"name":"Cape Verdean escudo","symbol":"Esc"}},"languages":{"por":"Portuguese"},"flag":"🇨🇻"},{"cca2":"CR","currencies":{"CRC":{"name":"Costa Rican colón","symbol":"₡"}},"languages":{"spa":"Spanish"},"flag":"🇨🇷"},{"cca2":"CU","currencies":{"CUC":{"name":"Cuban convertible peso","symbol":"$"},"CUP":{"name":"Cuban peso","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇨🇺"},{"cca2":"CW","currencies":{"ANG":{"name":"Netherlands Antillean guilder","symbol":"ƒ"}},"languages":{"eng":"English","nld":"Dutch","pap":"Papiamento"},"flag":"🇨🇼"},{"cca2":"CX","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇨🇽"},{"cca2":"KY","currencies":{"KYD":{"name":"Cayman Islands dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇰🇾"},{"cca2":"CY","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"ell":"Greek","tur":"Turkish"},"flag":"🇨🇾"},{"cca2":"CZ","currencies":{"CZK":{"name":"Czech koruna","symbol":"Kč"}},"languages":{"ces":"Czech","slk":"Slovak"},"flag":"🇨🇿"},{"cca2":"DE","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"deu":"German"},"flag":"🇩🇪"},{"cca2":"DJ","currencies":{"DJF":{"name":"Djiboutian franc","symbol":"Fr"}},"languages":{"ara":"Arabic","fra":"French"},"flag":"🇩🇯"},{"cca2":"DM","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇩🇲"},{"cca2":"DK","currencies":{"DKK":{"name":"Danish krone","symbol":"kr"}},"languages":{"dan":"Danish"},"flag":"🇩🇰"},{"cca2":"DO","currencies":{"DOP":{"name":"Dominican peso","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇩🇴"},{"cca2":"DZ","currencies":{"DZD":{"name":"Algerian dinar","symbol":"د.ج"}},"languages":{"ara":"Arabic"},"flag":"🇩🇿"},{"cca2":"EC","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇪🇨"},{"cca2":"EG","currencies":{"EGP":{"name":"Egyptian pound","symbol":"£"}},"languages":{"ara":"Arabic"},"flag":"🇪🇬"},{"cca2":"ER","currencies":{"ERN":{"name":"Eritrean nakfa","symbol":"Nfk"}},"languages":{"ara":"Arabic","eng":"English","tir":"Tigrinya"},"flag":"🇪🇷"},{"cca2":"EH","currencies":{"DZD":{"name":"Algerian dinar","symbol":"دج"},"MAD":{"name":"Moroccan dirham","symbol":"DH"},"MRU":{"name":"Mauritanian ouguiya","symbol":"UM"}},"languages":{"ber":"Berber","mey":"Hassaniya","spa":"Spanish"},"flag":"🇪🇭"},{"cca2":"ES","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"spa":"Spanish"},"flag":"🇪🇸"},{"cca2":"EE","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"est":"Estonian"},"flag":"🇪🇪"},{"cca2":"ET","currencies":{"ETB":{"name":"Ethiopian birr","symbol":"Br"}},"languages":{"amh":"Amharic"},"flag":"🇪🇹"},{"cca2":"FI","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fin":"Finnish","swe":"Swedish"},"flag":"🇫🇮"},{"cca2":"FJ","currencies":{"FJD":{"name":"Fijian dollar","symbol":"$"}},"languages":{"eng":"English","fij":"Fijian","hif":"Fiji Hindi"},"flag":"🇫🇯"},{"cca2":"FK","currencies":{"FKP":{"name":"Falkland Islands pound","symbol":"£"}},"languages":{"eng":"English"},"flag":"🇫🇰"},{"cca2":"FR","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇫🇷"},{"cca2":"FO","currencies":{"DKK":{"name":"Danish krone","symbol":"kr"},"FOK":{"name":"Faroese króna","symbol":"kr"}},"languages":{"dan":"Danish","fao":"Faroese"},"flag":"🇫🇴"},{"cca2":"FM","currencies":[],"languages":{"eng":"English"},"flag":"🇫🇲"},{"cca2":"GA","currencies":{"XAF":{"name":"Central African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇬🇦"},{"cca2":"GB","currencies":{"GBP":{"name":"British pound","symbol":"£"}},"languages":{"eng":"English"},"flag":"🇬🇧"},{"cca2":"GE","currencies":{"GEL":{"name":"lari","symbol":"₾"}},"languages":{"kat":"Georgian"},"flag":"🇬🇪"},{"cca2":"GG","currencies":{"GBP":{"name":"British pound","symbol":"£"},"GGP":{"name":"Guernsey pound","symbol":"£"}},"languages":{"eng":"English","fra":"French","nfr":"Guernésiais"},"flag":"🇬🇬"},{"cca2":"GH","currencies":{"GHS":{"name":"Ghanaian cedi","symbol":"₵"}},"languages":{"eng":"English"},"flag":"🇬🇭"},{"cca2":"GI","currencies":{"GIP":{"name":"Gibraltar pound","symbol":"£"}},"languages":{"eng":"English"},"flag":"🇬🇮"},{"cca2":"GN","currencies":{"GNF":{"name":"Guinean franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇬🇳"},{"cca2":"GP","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇬🇵"},{"cca2":"GM","currencies":{"GMD":{"name":"dalasi","symbol":"D"}},"languages":{"eng":"English"},"flag":"🇬🇲"},{"cca2":"GW","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"por":"Portuguese","pov":"Upper Guinea Creole"},"flag":"🇬🇼"},{"cca2":"GQ","currencies":{"XAF":{"name":"Central African CFA franc","symbol":"Fr"}},"languages":{"fra":"French","por":"Portuguese","spa":"Spanish"},"flag":"🇬🇶"},{"cca2":"GR","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"ell":"Greek"},"flag":"🇬🇷"},{"cca2":"GD","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇬🇩"},{"cca2":"GL","currencies":{"DKK":{"name":"krone","symbol":"kr."}},"languages":{"kal":"Greenlandic"},"flag":"🇬🇱"},{"cca2":"GT","currencies":{"GTQ":{"name":"Guatemalan quetzal","symbol":"Q"}},"languages":{"spa":"Spanish"},"flag":"🇬🇹"},{"cca2":"GF","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇬🇫"},{"cca2":"GU","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"cha":"Chamorro","eng":"English","spa":"Spanish"},"flag":"🇬🇺"},{"cca2":"GY","currencies":{"GYD":{"name":"Guyanese dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇬🇾"},{"cca2":"HK","currencies":{"HKD":{"name":"Hong Kong dollar","symbol":"$"}},"languages":{"eng":"English","zho":"Chinese"},"flag":"🇭🇰"},{"cca2":"HM","currencies":[],"languages":{"eng":"English"},"flag":"🇭🇲"},{"cca2":"HN","currencies":{"HNL":{"name":"Honduran lempira","symbol":"L"}},"languages":{"spa":"Spanish"},"flag":"🇭🇳"},{"cca2":"HR","currencies":{"HRK":{"name":"Croatian kuna","symbol":"kn"}},"languages":{"hrv":"Croatian"},"flag":"🇭🇷"},{"cca2":"HT","currencies":{"HTG":{"name":"Haitian gourde","symbol":"G"}},"languages":{"fra":"French","hat":"Haitian Creole"},"flag":"🇭🇹"},{"cca2":"HU","currencies":{"HUF":{"name":"Hungarian forint","symbol":"Ft"}},"languages":{"hun":"Hungarian"},"flag":"🇭🇺"},{"cca2":"ID","currencies":{"IDR":{"name":"Indonesian rupiah","symbol":"Rp"}},"languages":{"ind":"Indonesian"},"flag":"🇮🇩"},{"cca2":"IM","currencies":{"GBP":{"name":"British pound","symbol":"£"},"IMP":{"name":"Manx pound","symbol":"£"}},"languages":{"eng":"English","glv":"Manx"},"flag":"🇮🇲"},{"cca2":"IN","currencies":{"INR":{"name":"Indian rupee","symbol":"₹"}},"languages":{"eng":"English","hin":"Hindi","tam":"Tamil"},"flag":"🇮🇳"},{"cca2":"IO","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇮🇴"},{"cca2":"IE","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"eng":"English","gle":"Irish"},"flag":"🇮🇪"},{"cca2":"IR","currencies":{"IRR":{"name":"Iranian rial","symbol":"﷼"}},"languages":{"fas":"Persian (Farsi)"},"flag":"🇮🇷"},{"cca2":"IQ","currencies":{"IQD":{"name":"Iraqi dinar","symbol":"ع.د"}},"languages":{"ara":"Arabic","arc":"Aramaic","ckb":"Sorani"},"flag":"🇮🇶"},{"cca2":"IS","currencies":{"ISK":{"name":"Icelandic króna","symbol":"kr"}},"languages":{"isl":"Icelandic"},"flag":"🇮🇸"},{"cca2":"IL","currencies":{"ILS":{"name":"Israeli new shekel","symbol":"₪"}},"languages":{"ara":"Arabic","heb":"Hebrew"},"flag":"🇮🇱"},{"cca2":"IT","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"ita":"Italian"},"flag":"🇮🇹"},{"cca2":"JM","currencies":{"JMD":{"name":"Jamaican dollar","symbol":"$"}},"languages":{"eng":"English","jam":"Jamaican Patois"},"flag":"🇯🇲"},{"cca2":"JE","currencies":{"GBP":{"name":"British pound","symbol":"£"},"JEP":{"name":"Jersey pound","symbol":"£"}},"languages":{"eng":"English","fra":"French","nrf":"Jèrriais"},"flag":"🇯🇪"},{"cca2":"JO","currencies":{"JOD":{"name":"Jordanian dinar","symbol":"د.ا"}},"languages":{"ara":"Arabic"},"flag":"🇯🇴"},{"cca2":"JP","currencies":{"JPY":{"name":"Japanese yen","symbol":"¥"}},"languages":{"jpn":"Japanese"},"flag":"🇯🇵"},{"cca2":"KZ","currencies":{"KZT":{"name":"Kazakhstani tenge","symbol":"₸"}},"languages":{"kaz":"Kazakh","rus":"Russian"},"flag":"🇰🇿"},{"cca2":"KE","currencies":{"KES":{"name":"Kenyan shilling","symbol":"Sh"}},"languages":{"eng":"English","swa":"Swahili"},"flag":"🇰🇪"},{"cca2":"KG","currencies":{"KGS":{"name":"Kyrgyzstani som","symbol":"с"}},"languages":{"kir":"Kyrgyz","rus":"Russian"},"flag":"🇰🇬"},{"cca2":"KH","currencies":{"KHR":{"name":"Cambodian riel","symbol":"៛"},"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"khm":"Khmer"},"flag":"🇰🇭"},{"cca2":"KI","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"},"KID":{"name":"Kiribati dollar","symbol":"$"}},"languages":{"eng":"English","gil":"Gilbertese"},"flag":"🇰🇮"},{"cca2":"KN","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇰🇳"},{"cca2":"KR","currencies":{"KRW":{"name":"South Korean won","symbol":"₩"}},"languages":{"kor":"Korean"},"flag":"🇰🇷"},{"cca2":"XK","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"sqi":"Albanian","srp":"Serbian"},"flag":"🇽🇰"},{"cca2":"KW","currencies":{"KWD":{"name":"Kuwaiti dinar","symbol":"د.ك"}},"languages":{"ara":"Arabic"},"flag":"🇰🇼"},{"cca2":"LA","currencies":{"LAK":{"name":"Lao kip","symbol":"₭"}},"languages":{"lao":"Lao"},"flag":"🇱🇦"},{"cca2":"LB","currencies":{"LBP":{"name":"Lebanese pound","symbol":"ل.ل"}},"languages":{"ara":"Arabic","fra":"French"},"flag":"🇱🇧"},{"cca2":"LR","currencies":{"LRD":{"name":"Liberian dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇱🇷"},{"cca2":"LY","currencies":{"LYD":{"name":"Libyan dinar","symbol":"ل.د"}},"languages":{"ara":"Arabic"},"flag":"🇱🇾"},{"cca2":"LC","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇱🇨"},{"cca2":"LI","currencies":{"CHF":{"name":"Swiss franc","symbol":"Fr"}},"languages":{"deu":"German"},"flag":"🇱🇮"},{"cca2":"LK","currencies":{"LKR":{"name":"Sri Lankan rupee","symbol":"Rs රු"}},"languages":{"sin":"Sinhala","tam":"Tamil"},"flag":"🇱🇰"},{"cca2":"LS","currencies":{"LSL":{"name":"Lesotho loti","symbol":"L"},"ZAR":{"name":"South African rand","symbol":"R"}},"languages":{"eng":"English","sot":"Sotho"},"flag":"🇱🇸"},{"cca2":"LT","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"lit":"Lithuanian"},"flag":"🇱🇹"},{"cca2":"LU","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"deu":"German","fra":"French","ltz":"Luxembourgish"},"flag":"🇱🇺"},{"cca2":"LV","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"lav":"Latvian"},"flag":"🇱🇻"},{"cca2":"MO","currencies":{"MOP":{"name":"Macanese pataca","symbol":"P"}},"languages":{"por":"Portuguese","zho":"Chinese"},"flag":"🇲🇴"},{"cca2":"MF","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇲🇫"},{"cca2":"MA","currencies":{"MAD":{"name":"Moroccan dirham","symbol":"د.م."}},"languages":{"ara":"Arabic","ber":"Berber"},"flag":"🇲🇦"},{"cca2":"MC","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇲🇨"},{"cca2":"MD","currencies":{"MDL":{"name":"Moldovan leu","symbol":"L"}},"languages":{"ron":"Moldavian"},"flag":"🇲🇩"},{"cca2":"MG","currencies":{"MGA":{"name":"Malagasy ariary","symbol":"Ar"}},"languages":{"fra":"French","mlg":"Malagasy"},"flag":"🇲🇬"},{"cca2":"MV","currencies":{"MVR":{"name":"Maldivian rufiyaa","symbol":".ރ"}},"languages":{"div":"Maldivian"},"flag":"🇲🇻"},{"cca2":"MX","currencies":{"MXN":{"name":"Mexican peso","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇲🇽"},{"cca2":"MH","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English","mah":"Marshallese"},"flag":"🇲🇭"},{"cca2":"MK","currencies":{"MKD":{"name":"denar","symbol":"den"}},"languages":{"mkd":"Macedonian"},"flag":"🇲🇰"},{"cca2":"ML","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇲🇱"},{"cca2":"MT","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"eng":"English","mlt":"Maltese"},"flag":"🇲🇹"},{"cca2":"MM","currencies":{"MMK":{"name":"Burmese kyat","symbol":"Ks"}},"languages":{"mya":"Burmese"},"flag":"🇲🇲"},{"cca2":"ME","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"cnr":"Montenegrin"},"flag":"🇲🇪"},{"cca2":"MN","currencies":{"MNT":{"name":"Mongolian tögrög","symbol":"₮"}},"languages":{"mon":"Mongolian"},"flag":"🇲🇳"},{"cca2":"MP","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"cal":"Carolinian","cha":"Chamorro","eng":"English"},"flag":"🇲🇵"},{"cca2":"MZ","currencies":{"MZN":{"name":"Mozambican metical","symbol":"MT"}},"languages":{"por":"Portuguese"},"flag":"🇲🇿"},{"cca2":"MR","currencies":{"MRU":{"name":"Mauritanian ouguiya","symbol":"UM"}},"languages":{"ara":"Arabic"},"flag":"🇲🇷"},{"cca2":"MS","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇲🇸"},{"cca2":"MQ","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇲🇶"},{"cca2":"MU","currencies":{"MUR":{"name":"Mauritian rupee","symbol":"₨"}},"languages":{"eng":"English","fra":"French","mfe":"Mauritian Creole"},"flag":"🇲🇺"},{"cca2":"MW","currencies":{"MWK":{"name":"Malawian kwacha","symbol":"MK"}},"languages":{"eng":"English","nya":"Chewa"},"flag":"🇲🇼"},{"cca2":"MY","currencies":{"MYR":{"name":"Malaysian ringgit","symbol":"RM"}},"languages":{"eng":"English","msa":"Malay"},"flag":"🇲🇾"},{"cca2":"YT","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇾🇹"},{"cca2":"NA","currencies":{"NAD":{"name":"Namibian dollar","symbol":"$"},"ZAR":{"name":"South African rand","symbol":"R"}},"languages":{"afr":"Afrikaans","deu":"German","eng":"English","her":"Herero","hgm":"Khoekhoe","kwn":"Kwangali","loz":"Lozi","ndo":"Ndonga","tsn":"Tswana"},"flag":"🇳🇦"},{"cca2":"NC","currencies":{"XPF":{"name":"CFP franc","symbol":"₣"}},"languages":{"fra":"French"},"flag":"🇳🇨"},{"cca2":"NE","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇳🇪"},{"cca2":"NF","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"}},"languages":{"eng":"English","pih":"Norfuk"},"flag":"🇳🇫"},{"cca2":"NG","currencies":{"NGN":{"name":"Nigerian naira","symbol":"₦"}},"languages":{"eng":"English"},"flag":"🇳🇬"},{"cca2":"NI","currencies":{"NIO":{"name":"Nicaraguan córdoba","symbol":"C$"}},"languages":{"spa":"Spanish"},"flag":"🇳🇮"},{"cca2":"NU","currencies":{"NZD":{"name":"New Zealand dollar","symbol":"$"}},"languages":{"eng":"English","niu":"Niuean"},"flag":"🇳🇺"},{"cca2":"NL","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"nld":"Dutch"},"flag":"🇳🇱"},{"cca2":"NO","currencies":{"NOK":{"name":"Norwegian krone","symbol":"kr"}},"languages":{"nno":"Norwegian Nynorsk","nob":"Norwegian Bokmål","smi":"Sami"},"flag":"🇳🇴"},{"cca2":"NP","currencies":{"NPR":{"name":"Nepalese rupee","symbol":"₨"}},"languages":{"nep":"Nepali"},"flag":"🇳🇵"},{"cca2":"NR","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"}},"languages":{"eng":"English","nau":"Nauru"},"flag":"🇳🇷"},{"cca2":"NZ","currencies":{"NZD":{"name":"New Zealand dollar","symbol":"$"}},"languages":{"eng":"English","mri":"Māori","nzs":"New Zealand Sign Language"},"flag":"🇳🇿"},{"cca2":"OM","currencies":{"OMR":{"name":"Omani rial","symbol":"ر.ع."}},"languages":{"ara":"Arabic"},"flag":"🇴🇲"},{"cca2":"PK","currencies":{"PKR":{"name":"Pakistani rupee","symbol":"₨"}},"languages":{"eng":"English","urd":"Urdu"},"flag":"🇵🇰"},{"cca2":"PA","currencies":{"PAB":{"name":"Panamanian balboa","symbol":"B/."},"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇵🇦"},{"cca2":"PN","currencies":{"NZD":{"name":"New Zealand dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇵🇳"},{"cca2":"PE","currencies":{"PEN":{"name":"Peruvian sol","symbol":"S/."}},"languages":{"aym":"Aymara","que":"Quechua","spa":"Spanish"},"flag":"🇵🇪"},{"cca2":"PH","currencies":{"PHP":{"name":"Philippine peso","symbol":"₱"}},"languages":{"eng":"English","fil":"Filipino"},"flag":"🇵🇭"},{"cca2":"PW","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English","pau":"Palauan"},"flag":"🇵🇼"},{"cca2":"PG","currencies":{"PGK":{"name":"Papua New Guinean kina","symbol":"K"}},"languages":{"eng":"English","hmo":"Hiri Motu","tpi":"Tok Pisin"},"flag":"🇵🇬"},{"cca2":"PL","currencies":{"PLN":{"name":"Polish złoty","symbol":"zł"}},"languages":{"pol":"Polish"},"flag":"🇵🇱"},{"cca2":"PR","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English","spa":"Spanish"},"flag":"🇵🇷"},{"cca2":"KP","currencies":{"KPW":{"name":"North Korean won","symbol":"₩"}},"languages":{"kor":"Korean"},"flag":"🇰🇵"},{"cca2":"PT","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"por":"Portuguese"},"flag":"🇵🇹"},{"cca2":"PY","currencies":{"PYG":{"name":"Paraguayan guaraní","symbol":"₲"}},"languages":{"grn":"Guaraní","spa":"Spanish"},"flag":"🇵🇾"},{"cca2":"PS","currencies":{"EGP":{"name":"Egyptian pound","symbol":"E£"},"ILS":{"name":"Israeli new shekel","symbol":"₪"},"JOD":{"name":"Jordanian dinar","symbol":"JD"}},"languages":{"ara":"Arabic"},"flag":"🇵🇸"},{"cca2":"PF","currencies":{"XPF":{"name":"CFP franc","symbol":"₣"}},"languages":{"fra":"French"},"flag":"🇵🇫"},{"cca2":"QA","currencies":{"QAR":{"name":"Qatari riyal","symbol":"ر.ق"}},"languages":{"ara":"Arabic"},"flag":"🇶🇦"},{"cca2":"RE","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇷🇪"},{"cca2":"RO","currencies":{"RON":{"name":"Romanian leu","symbol":"lei"}},"languages":{"ron":"Romanian"},"flag":"🇷🇴"},{"cca2":"RU","currencies":{"RUB":{"name":"Russian ruble","symbol":"₽"}},"languages":{"rus":"Russian"},"flag":"🇷🇺"},{"cca2":"RW","currencies":{"RWF":{"name":"Rwandan franc","symbol":"Fr"}},"languages":{"eng":"English","fra":"French","kin":"Kinyarwanda"},"flag":"🇷🇼"},{"cca2":"SA","currencies":{"SAR":{"name":"Saudi riyal","symbol":"ر.س"}},"languages":{"ara":"Arabic"},"flag":"🇸🇦"},{"cca2":"SD","currencies":{"SDG":{"name":"Sudanese pound","symbol":""}},"languages":{"ara":"Arabic","eng":"English"},"flag":"🇸🇩"},{"cca2":"SN","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇸🇳"},{"cca2":"SG","currencies":{"SGD":{"name":"Singapore dollar","symbol":"$"}},"languages":{"zho":"Chinese","eng":"English","msa":"Malay","tam":"Tamil"},"flag":"🇸🇬"},{"cca2":"GS","currencies":{"SHP":{"name":"Saint Helena pound","symbol":"£"}},"languages":{"eng":"English"},"flag":"🇬🇸"},{"cca2":"SJ","currencies":{"NOK":{"name":"krone","symbol":"kr"}},"languages":{"nor":"Norwegian"},"flag":"🇸🇯"},{"cca2":"SB","currencies":{"SBD":{"name":"Solomon Islands dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇸🇧"},{"cca2":"SL","currencies":{"SLL":{"name":"Sierra Leonean leone","symbol":"Le"}},"languages":{"eng":"English"},"flag":"🇸🇱"},{"cca2":"SV","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇸🇻"},{"cca2":"SM","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"ita":"Italian"},"flag":"🇸🇲"},{"cca2":"SO","currencies":{"SOS":{"name":"Somali shilling","symbol":"Sh"}},"languages":{"ara":"Arabic","som":"Somali"},"flag":"🇸🇴"},{"cca2":"PM","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"fra":"French"},"flag":"🇵🇲"},{"cca2":"RS","currencies":{"RSD":{"name":"Serbian dinar","symbol":"дин."}},"languages":{"srp":"Serbian"},"flag":"🇷🇸"},{"cca2":"SS","currencies":{"SSP":{"name":"South Sudanese pound","symbol":"£"}},"languages":{"eng":"English"},"flag":"🇸🇸"},{"cca2":"ST","currencies":{"STN":{"name":"São Tomé and Príncipe dobra","symbol":"Db"}},"languages":{"por":"Portuguese"},"flag":"🇸🇹"},{"cca2":"SR","currencies":{"SRD":{"name":"Surinamese dollar","symbol":"$"}},"languages":{"nld":"Dutch"},"flag":"🇸🇷"},{"cca2":"SK","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"slk":"Slovak"},"flag":"🇸🇰"},{"cca2":"SI","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"slv":"Slovene"},"flag":"🇸🇮"},{"cca2":"SE","currencies":{"SEK":{"name":"Swedish krona","symbol":"kr"}},"languages":{"swe":"Swedish"},"flag":"🇸🇪"},{"cca2":"SZ","currencies":{"SZL":{"name":"Swazi lilangeni","symbol":"L"},"ZAR":{"name":"South African rand","symbol":"R"}},"languages":{"eng":"English","ssw":"Swazi"},"flag":"🇸🇿"},{"cca2":"SX","currencies":{"ANG":{"name":"Netherlands Antillean guilder","symbol":"ƒ"}},"languages":{"eng":"English","fra":"French","nld":"Dutch"},"flag":"🇸🇽"},{"cca2":"SC","currencies":{"SCR":{"name":"Seychellois rupee","symbol":"₨"}},"languages":{"crs":"Seychellois Creole","eng":"English","fra":"French"},"flag":"🇸🇨"},{"cca2":"SY","currencies":{"SYP":{"name":"Syrian pound","symbol":"£"}},"languages":{"ara":"Arabic"},"flag":"🇸🇾"},{"cca2":"TC","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇹🇨"},{"cca2":"TD","currencies":{"XAF":{"name":"Central African CFA franc","symbol":"Fr"}},"languages":{"ara":"Arabic","fra":"French"},"flag":"🇹🇩"},{"cca2":"TG","currencies":{"XOF":{"name":"West African CFA franc","symbol":"Fr"}},"languages":{"fra":"French"},"flag":"🇹🇬"},{"cca2":"TH","currencies":{"THB":{"name":"Thai baht","symbol":"฿"}},"languages":{"tha":"Thai"},"flag":"🇹🇭"},{"cca2":"TJ","currencies":{"TJS":{"name":"Tajikistani somoni","symbol":"ЅМ"}},"languages":{"rus":"Russian","tgk":"Tajik"},"flag":"🇹🇯"},{"cca2":"TK","currencies":{"NZD":{"name":"New Zealand dollar","symbol":"$"}},"languages":{"eng":"English","smo":"Samoan","tkl":"Tokelauan"},"flag":"🇹🇰"},{"cca2":"TM","currencies":{"TMT":{"name":"Turkmenistan manat","symbol":"m"}},"languages":{"rus":"Russian","tuk":"Turkmen"},"flag":"🇹🇲"},{"cca2":"TL","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"por":"Portuguese","tet":"Tetum"},"flag":"🇹🇱"},{"cca2":"TO","currencies":{"TOP":{"name":"Tongan paʻanga","symbol":"T$"}},"languages":{"eng":"English","ton":"Tongan"},"flag":"🇹🇴"},{"cca2":"TT","currencies":{"TTD":{"name":"Trinidad and Tobago dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇹🇹"},{"cca2":"TN","currencies":{"TND":{"name":"Tunisian dinar","symbol":"د.ت"}},"languages":{"ara":"Arabic"},"flag":"🇹🇳"},{"cca2":"TR","currencies":{"TRY":{"name":"Turkish lira","symbol":"₺"}},"languages":{"tur":"Turkish"},"flag":"🇹🇷"},{"cca2":"TV","currencies":{"AUD":{"name":"Australian dollar","symbol":"$"},"TVD":{"name":"Tuvaluan dollar","symbol":"$"}},"languages":{"eng":"English","tvl":"Tuvaluan"},"flag":"🇹🇻"},{"cca2":"TW","currencies":{"TWD":{"name":"New Taiwan dollar","symbol":"$"}},"languages":{"zho":"Chinese"},"flag":"🇹🇼"},{"cca2":"TZ","currencies":{"TZS":{"name":"Tanzanian shilling","symbol":"Sh"}},"languages":{"eng":"English","swa":"Swahili"},"flag":"🇹🇿"},{"cca2":"UG","currencies":{"UGX":{"name":"Ugandan shilling","symbol":"Sh"}},"languages":{"eng":"English","swa":"Swahili"},"flag":"🇺🇬"},{"cca2":"UA","currencies":{"UAH":{"name":"Ukrainian hryvnia","symbol":"₴"}},"languages":{"ukr":"Ukrainian"},"flag":"🇺🇦"},{"cca2":"UM","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇺🇲"},{"cca2":"UY","currencies":{"UYU":{"name":"Uruguayan peso","symbol":"$"}},"languages":{"spa":"Spanish"},"flag":"🇺🇾"},{"cca2":"US","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇺🇸"},{"cca2":"UZ","currencies":{"UZS":{"name":"Uzbekistani soʻm","symbol":"so'm"}},"languages":{"rus":"Russian","uzb":"Uzbek"},"flag":"🇺🇿"},{"cca2":"VA","currencies":{"EUR":{"name":"Euro","symbol":"€"}},"languages":{"ita":"Italian","lat":"Latin"},"flag":"🇻🇦"},{"cca2":"VC","currencies":{"XCD":{"name":"Eastern Caribbean dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇻🇨"},{"cca2":"VE","currencies":{"VES":{"name":"Venezuelan bolívar soberano","symbol":"Bs.S."}},"languages":{"spa":"Spanish"},"flag":"🇻🇪"},{"cca2":"VG","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇻🇬"},{"cca2":"VI","currencies":{"USD":{"name":"United States dollar","symbol":"$"}},"languages":{"eng":"English"},"flag":"🇻🇮"},{"cca2":"VN","currencies":{"VND":{"name":"Vietnamese đồng","symbol":"₫"}},"languages":{"vie":"Vietnamese"},"flag":"🇻🇳"},{"cca2":"VU","currencies":{"VUV":{"name":"Vanuatu vatu","symbol":"Vt"}},"languages":{"bis":"Bislama","eng":"English","fra":"French"},"flag":"🇻🇺"},{"cca2":"WF","currencies":{"XPF":{"name":"CFP franc","symbol":"₣"}},"languages":{"fra":"French"},"flag":"🇼🇫"},{"cca2":"WS","currencies":{"WST":{"name":"Samoan tālā","symbol":"T"}},"languages":{"eng":"English","smo":"Samoan"},"flag":"🇼🇸"},{"cca2":"YE","currencies":{"YER":{"name":"Yemeni rial","symbol":"﷼"}},"languages":{"ara":"Arabic"},"flag":"🇾🇪"},{"cca2":"ZA","currencies":{"ZAR":{"name":"South African rand","symbol":"R"}},"languages":{"afr":"Afrikaans","eng":"English","nbl":"Southern Ndebele","nso":"Northern Sotho","sot":"Southern Sotho","ssw":"Swazi","tsn":"Tswana","tso":"Tsonga","ven":"Venda","xho":"Xhosa","zul":"Zulu"},"flag":"🇿🇦"},{"cca2":"ZM","currencies":{"ZMW":{"name":"Zambian kwacha","symbol":"ZK"}},"languages":{"eng":"English"},"flag":"🇿🇲"},{"cca2":"ZW","currencies":{"BWP":{"name":"Botswana pula","symbol":"P"},"CNY":{"name":"Chinese yuan","symbol":"¥"},"EUR":{"name":"Euro","symbol":"€"},"GBP":{"name":"British pound","symbol":"£"},"INR":{"name":"Indian rupee","symbol":"₹"},"JPY":{"name":"Japanese yen","symbol":"¥"},"USD":{"name":"United States dollar","symbol":"$"},"ZAR":{"name":"South African rand","symbol":"Rs"},"ZWB":{"name":"Zimbabwean bonds","symbol":"$"}},"languages":{"bwg":"Chibarwe","eng":"English","kck":"Kalanga","khi":"Khoisan","ndc":"Ndau","nde":"Northern Ndebele","nya":"Chewa","sna":"Shona","sot":"Sotho","toi":"Tonga","tsn":"Tswana","tso":"Tsonga","ven":"Venda","xho":"Xhosa","zib":"Zimbabwean Sign Language"},"flag":"🇿🇼"}] \ No newline at end of file +[ + { + "cca2": "AW", + "currencies": { "AWG": { "name": "Aruban florin", "symbol": "ƒ" } }, + "languages": { "nld": "Dutch", "pap": "Papiamento" }, + "flag": "🇦🇼" + }, + { + "cca2": "AF", + "currencies": { "AFN": { "name": "Afghan afghani", "symbol": "؋" } }, + "languages": { "prs": "Dari", "pus": "Pashto", "tuk": "Turkmen" }, + "flag": "🇦🇫" + }, + { + "cca2": "AO", + "currencies": { "AOA": { "name": "Angolan kwanza", "symbol": "Kz" } }, + "languages": { "por": "Portuguese" }, + "flag": "🇦🇴" + }, + { + "cca2": "AI", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇦🇮" + }, + { + "cca2": "AX", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "swe": "Swedish" }, + "flag": "🇦🇽" + }, + { + "cca2": "AL", + "currencies": { "ALL": { "name": "Albanian lek", "symbol": "L" } }, + "languages": { "sqi": "Albanian" }, + "flag": "🇦🇱" + }, + { + "cca2": "AD", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "cat": "Catalan" }, + "flag": "🇦🇩" + }, + { + "cca2": "AE", + "currencies": { + "AED": { "name": "United Arab Emirates dirham", "symbol": "د.إ" } + }, + "languages": { "ara": "Arabic" }, + "flag": "🇦🇪" + }, + { + "cca2": "AR", + "currencies": { "ARS": { "name": "Argentine peso", "symbol": "$" } }, + "languages": { "grn": "Guaraní", "spa": "Spanish" }, + "flag": "🇦🇷" + }, + { + "cca2": "AM", + "currencies": { "AMD": { "name": "Armenian dram", "symbol": "֏" } }, + "languages": { "hye": "Armenian" }, + "flag": "🇦🇲" + }, + { + "cca2": "AS", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English", "smo": "Samoan" }, + "flag": "🇦🇸" + }, + { "cca2": "AQ", "currencies": [], "languages": {}, "flag": "🇦🇶" }, + { + "cca2": "TF", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇹🇫" + }, + { + "cca2": "AG", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇦🇬" + }, + { + "cca2": "AU", + "currencies": { "AUD": { "name": "Australian dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇦🇺" + }, + { + "cca2": "AT", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "bar": "Austro-Bavarian German" }, + "flag": "🇦🇹" + }, + { + "cca2": "AZ", + "currencies": { "AZN": { "name": "Azerbaijani manat", "symbol": "₼" } }, + "languages": { "aze": "Azerbaijani", "rus": "Russian" }, + "flag": "🇦🇿" + }, + { + "cca2": "BI", + "currencies": { "BIF": { "name": "Burundian franc", "symbol": "Fr" } }, + "languages": { "fra": "French", "run": "Kirundi" }, + "flag": "🇧🇮" + }, + { + "cca2": "BE", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "deu": "German", "fra": "French", "nld": "Dutch" }, + "flag": "🇧🇪" + }, + { + "cca2": "BJ", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇧🇯" + }, + { + "cca2": "BF", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇧🇫" + }, + { + "cca2": "BD", + "currencies": { "BDT": { "name": "Bangladeshi taka", "symbol": "৳" } }, + "languages": { "ben": "Bengali" }, + "flag": "🇧🇩" + }, + { + "cca2": "BG", + "currencies": { "BGN": { "name": "Bulgarian lev", "symbol": "лв" } }, + "languages": { "bul": "Bulgarian" }, + "flag": "🇧🇬" + }, + { + "cca2": "BH", + "currencies": { "BHD": { "name": "Bahraini dinar", "symbol": ".د.ب" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇧🇭" + }, + { + "cca2": "BS", + "currencies": { + "BSD": { "name": "Bahamian dollar", "symbol": "$" }, + "USD": { "name": "United States dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇧🇸" + }, + { + "cca2": "BA", + "currencies": { + "BAM": { "name": "Bosnia and Herzegovina convertible mark", "symbol": "" } + }, + "languages": { "bos": "Bosnian", "hrv": "Croatian", "srp": "Serbian" }, + "flag": "🇧🇦" + }, + { + "cca2": "BL", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇧🇱" + }, + { + "cca2": "SH", + "currencies": { + "GBP": { "name": "Pound sterling", "symbol": "£" }, + "SHP": { "name": "Saint Helena pound", "symbol": "£" } + }, + "languages": { "eng": "English" }, + "flag": "🇸🇭" + }, + { + "cca2": "BY", + "currencies": { "BYN": { "name": "Belarusian ruble", "symbol": "Br" } }, + "languages": { "bel": "Belarusian", "rus": "Russian" }, + "flag": "🇧🇾" + }, + { + "cca2": "BZ", + "currencies": { "BZD": { "name": "Belize dollar", "symbol": "$" } }, + "languages": { + "bjz": "Belizean Creole", + "eng": "English", + "spa": "Spanish" + }, + "flag": "🇧🇿" + }, + { + "cca2": "BM", + "currencies": { "BMD": { "name": "Bermudian dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇧🇲" + }, + { + "cca2": "BO", + "currencies": { "BOB": { "name": "Bolivian boliviano", "symbol": "Bs." } }, + "languages": { + "aym": "Aymara", + "grn": "Guaraní", + "que": "Quechua", + "spa": "Spanish" + }, + "flag": "🇧🇴" + }, + { + "cca2": "BQ", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English", "nld": "Dutch", "pap": "Papiamento" }, + "flag": "" + }, + { + "cca2": "BR", + "currencies": { "BRL": { "name": "Brazilian real", "symbol": "R$" } }, + "languages": { "por": "Portuguese" }, + "flag": "🇧🇷" + }, + { + "cca2": "BB", + "currencies": { "BBD": { "name": "Barbadian dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇧🇧" + }, + { + "cca2": "BN", + "currencies": { + "BND": { "name": "Brunei dollar", "symbol": "$" }, + "SGD": { "name": "Singapore dollar", "symbol": "$" } + }, + "languages": { "msa": "Malay" }, + "flag": "🇧🇳" + }, + { + "cca2": "BT", + "currencies": { + "BTN": { "name": "Bhutanese ngultrum", "symbol": "Nu." }, + "INR": { "name": "Indian rupee", "symbol": "₹" } + }, + "languages": { "dzo": "Dzongkha" }, + "flag": "🇧🇹" + }, + { + "cca2": "BV", + "currencies": [], + "languages": { "nor": "Norwegian" }, + "flag": "🇧🇻" + }, + { + "cca2": "BW", + "currencies": { "BWP": { "name": "Botswana pula", "symbol": "P" } }, + "languages": { "eng": "English", "tsn": "Tswana" }, + "flag": "🇧🇼" + }, + { + "cca2": "CF", + "currencies": { + "XAF": { "name": "Central African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French", "sag": "Sango" }, + "flag": "🇨🇫" + }, + { + "cca2": "CA", + "currencies": { "CAD": { "name": "Canadian dollar", "symbol": "$" } }, + "languages": { "eng": "English", "fra": "French" }, + "flag": "🇨🇦" + }, + { + "cca2": "CC", + "currencies": { "AUD": { "name": "Australian dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇨🇨" + }, + { + "cca2": "CH", + "currencies": { "CHF": { "name": "Swiss franc", "symbol": "Fr." } }, + "languages": { + "fra": "French", + "gsw": "Swiss German", + "ita": "Italian", + "roh": "Romansh" + }, + "flag": "🇨🇭" + }, + { + "cca2": "CL", + "currencies": { "CLP": { "name": "Chilean peso", "symbol": "$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇨🇱" + }, + { + "cca2": "CN", + "currencies": { "CNY": { "name": "Chinese yuan", "symbol": "¥" } }, + "languages": { "zho": "Chinese" }, + "flag": "🇨🇳" + }, + { + "cca2": "CI", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇨🇮" + }, + { + "cca2": "CM", + "currencies": { + "XAF": { "name": "Central African CFA franc", "symbol": "Fr" } + }, + "languages": { "eng": "English", "fra": "French" }, + "flag": "🇨🇲" + }, + { + "cca2": "CD", + "currencies": { "CDF": { "name": "Congolese franc", "symbol": "FC" } }, + "languages": { + "fra": "French", + "kon": "Kikongo", + "lin": "Lingala", + "lua": "Tshiluba", + "swa": "Swahili" + }, + "flag": "🇨🇩" + }, + { + "cca2": "CG", + "currencies": { + "XAF": { "name": "Central African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French", "kon": "Kikongo", "lin": "Lingala" }, + "flag": "🇨🇬" + }, + { + "cca2": "CK", + "currencies": { + "CKD": { "name": "Cook Islands dollar", "symbol": "$" }, + "NZD": { "name": "New Zealand dollar", "symbol": "$" } + }, + "languages": { "eng": "English", "rar": "Cook Islands Māori" }, + "flag": "🇨🇰" + }, + { + "cca2": "CO", + "currencies": { "COP": { "name": "Colombian peso", "symbol": "$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇨🇴" + }, + { + "cca2": "KM", + "currencies": { "KMF": { "name": "Comorian franc", "symbol": "Fr" } }, + "languages": { "ara": "Arabic", "fra": "French", "zdj": "Comorian" }, + "flag": "🇰🇲" + }, + { + "cca2": "CV", + "currencies": { "CVE": { "name": "Cape Verdean escudo", "symbol": "Esc" } }, + "languages": { "por": "Portuguese" }, + "flag": "🇨🇻" + }, + { + "cca2": "CR", + "currencies": { "CRC": { "name": "Costa Rican colón", "symbol": "₡" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇨🇷" + }, + { + "cca2": "CU", + "currencies": { + "CUC": { "name": "Cuban convertible peso", "symbol": "$" }, + "CUP": { "name": "Cuban peso", "symbol": "$" } + }, + "languages": { "spa": "Spanish" }, + "flag": "🇨🇺" + }, + { + "cca2": "CW", + "currencies": { + "ANG": { "name": "Netherlands Antillean guilder", "symbol": "ƒ" } + }, + "languages": { "eng": "English", "nld": "Dutch", "pap": "Papiamento" }, + "flag": "🇨🇼" + }, + { + "cca2": "CX", + "currencies": { "AUD": { "name": "Australian dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇨🇽" + }, + { + "cca2": "KY", + "currencies": { "KYD": { "name": "Cayman Islands dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇰🇾" + }, + { + "cca2": "CY", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "ell": "Greek", "tur": "Turkish" }, + "flag": "🇨🇾" + }, + { + "cca2": "CZ", + "currencies": { "CZK": { "name": "Czech koruna", "symbol": "Kč" } }, + "languages": { "ces": "Czech", "slk": "Slovak" }, + "flag": "🇨🇿" + }, + { + "cca2": "DE", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "deu": "German" }, + "flag": "🇩🇪" + }, + { + "cca2": "DJ", + "currencies": { "DJF": { "name": "Djiboutian franc", "symbol": "Fr" } }, + "languages": { "ara": "Arabic", "fra": "French" }, + "flag": "🇩🇯" + }, + { + "cca2": "DM", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇩🇲" + }, + { + "cca2": "DK", + "currencies": { "DKK": { "name": "Danish krone", "symbol": "kr" } }, + "languages": { "dan": "Danish" }, + "flag": "🇩🇰" + }, + { + "cca2": "DO", + "currencies": { "DOP": { "name": "Dominican peso", "symbol": "$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇩🇴" + }, + { + "cca2": "DZ", + "currencies": { "DZD": { "name": "Algerian dinar", "symbol": "د.ج" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇩🇿" + }, + { + "cca2": "EC", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇪🇨" + }, + { + "cca2": "EG", + "currencies": { "EGP": { "name": "Egyptian pound", "symbol": "£" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇪🇬" + }, + { + "cca2": "ER", + "currencies": { "ERN": { "name": "Eritrean nakfa", "symbol": "Nfk" } }, + "languages": { "ara": "Arabic", "eng": "English", "tir": "Tigrinya" }, + "flag": "🇪🇷" + }, + { + "cca2": "EH", + "currencies": { + "DZD": { "name": "Algerian dinar", "symbol": "دج" }, + "MAD": { "name": "Moroccan dirham", "symbol": "DH" }, + "MRU": { "name": "Mauritanian ouguiya", "symbol": "UM" } + }, + "languages": { "ber": "Berber", "mey": "Hassaniya", "spa": "Spanish" }, + "flag": "🇪🇭" + }, + { + "cca2": "ES", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇪🇸" + }, + { + "cca2": "EE", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "est": "Estonian" }, + "flag": "🇪🇪" + }, + { + "cca2": "ET", + "currencies": { "ETB": { "name": "Ethiopian birr", "symbol": "Br" } }, + "languages": { "amh": "Amharic" }, + "flag": "🇪🇹" + }, + { + "cca2": "FI", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fin": "Finnish", "swe": "Swedish" }, + "flag": "🇫🇮" + }, + { + "cca2": "FJ", + "currencies": { "FJD": { "name": "Fijian dollar", "symbol": "$" } }, + "languages": { "eng": "English", "fij": "Fijian", "hif": "Fiji Hindi" }, + "flag": "🇫🇯" + }, + { + "cca2": "FK", + "currencies": { + "FKP": { "name": "Falkland Islands pound", "symbol": "£" } + }, + "languages": { "eng": "English" }, + "flag": "🇫🇰" + }, + { + "cca2": "FR", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇫🇷" + }, + { + "cca2": "FO", + "currencies": { + "DKK": { "name": "Danish krone", "symbol": "kr" }, + "FOK": { "name": "Faroese króna", "symbol": "kr" } + }, + "languages": { "dan": "Danish", "fao": "Faroese" }, + "flag": "🇫🇴" + }, + { + "cca2": "FM", + "currencies": [], + "languages": { "eng": "English" }, + "flag": "🇫🇲" + }, + { + "cca2": "GA", + "currencies": { + "XAF": { "name": "Central African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇬🇦" + }, + { + "cca2": "GB", + "currencies": { "GBP": { "name": "British pound", "symbol": "£" } }, + "languages": { "eng": "English" }, + "flag": "🇬🇧" + }, + { + "cca2": "GE", + "currencies": { "GEL": { "name": "lari", "symbol": "₾" } }, + "languages": { "kat": "Georgian" }, + "flag": "🇬🇪" + }, + { + "cca2": "GG", + "currencies": { + "GBP": { "name": "British pound", "symbol": "£" }, + "GGP": { "name": "Guernsey pound", "symbol": "£" } + }, + "languages": { "eng": "English", "fra": "French", "nfr": "Guernésiais" }, + "flag": "🇬🇬" + }, + { + "cca2": "GH", + "currencies": { "GHS": { "name": "Ghanaian cedi", "symbol": "₵" } }, + "languages": { "eng": "English" }, + "flag": "🇬🇭" + }, + { + "cca2": "GI", + "currencies": { "GIP": { "name": "Gibraltar pound", "symbol": "£" } }, + "languages": { "eng": "English" }, + "flag": "🇬🇮" + }, + { + "cca2": "GN", + "currencies": { "GNF": { "name": "Guinean franc", "symbol": "Fr" } }, + "languages": { "fra": "French" }, + "flag": "🇬🇳" + }, + { + "cca2": "GP", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇬🇵" + }, + { + "cca2": "GM", + "currencies": { "GMD": { "name": "dalasi", "symbol": "D" } }, + "languages": { "eng": "English" }, + "flag": "🇬🇲" + }, + { + "cca2": "GW", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "por": "Portuguese", "pov": "Upper Guinea Creole" }, + "flag": "🇬🇼" + }, + { + "cca2": "GQ", + "currencies": { + "XAF": { "name": "Central African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French", "por": "Portuguese", "spa": "Spanish" }, + "flag": "🇬🇶" + }, + { + "cca2": "GR", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "ell": "Greek" }, + "flag": "🇬🇷" + }, + { + "cca2": "GD", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇬🇩" + }, + { + "cca2": "GL", + "currencies": { "DKK": { "name": "krone", "symbol": "kr." } }, + "languages": { "kal": "Greenlandic" }, + "flag": "🇬🇱" + }, + { + "cca2": "GT", + "currencies": { "GTQ": { "name": "Guatemalan quetzal", "symbol": "Q" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇬🇹" + }, + { + "cca2": "GF", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇬🇫" + }, + { + "cca2": "GU", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "cha": "Chamorro", "eng": "English", "spa": "Spanish" }, + "flag": "🇬🇺" + }, + { + "cca2": "GY", + "currencies": { "GYD": { "name": "Guyanese dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇬🇾" + }, + { + "cca2": "HK", + "currencies": { "HKD": { "name": "Hong Kong dollar", "symbol": "$" } }, + "languages": { "eng": "English", "zho": "Chinese" }, + "flag": "🇭🇰" + }, + { + "cca2": "HM", + "currencies": [], + "languages": { "eng": "English" }, + "flag": "🇭🇲" + }, + { + "cca2": "HN", + "currencies": { "HNL": { "name": "Honduran lempira", "symbol": "L" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇭🇳" + }, + { + "cca2": "HR", + "currencies": { "HRK": { "name": "Croatian kuna", "symbol": "kn" } }, + "languages": { "hrv": "Croatian" }, + "flag": "🇭🇷" + }, + { + "cca2": "HT", + "currencies": { "HTG": { "name": "Haitian gourde", "symbol": "G" } }, + "languages": { "fra": "French", "hat": "Haitian Creole" }, + "flag": "🇭🇹" + }, + { + "cca2": "HU", + "currencies": { "HUF": { "name": "Hungarian forint", "symbol": "Ft" } }, + "languages": { "hun": "Hungarian" }, + "flag": "🇭🇺" + }, + { + "cca2": "ID", + "currencies": { "IDR": { "name": "Indonesian rupiah", "symbol": "Rp" } }, + "languages": { "ind": "Indonesian" }, + "flag": "🇮🇩" + }, + { + "cca2": "IM", + "currencies": { + "GBP": { "name": "British pound", "symbol": "£" }, + "IMP": { "name": "Manx pound", "symbol": "£" } + }, + "languages": { "eng": "English", "glv": "Manx" }, + "flag": "🇮🇲" + }, + { + "cca2": "IN", + "currencies": { "INR": { "name": "Indian rupee", "symbol": "₹" } }, + "languages": { "eng": "English", "hin": "Hindi", "tam": "Tamil" }, + "flag": "🇮🇳" + }, + { + "cca2": "IO", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇮🇴" + }, + { + "cca2": "IE", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "eng": "English", "gle": "Irish" }, + "flag": "🇮🇪" + }, + { + "cca2": "IR", + "currencies": { "IRR": { "name": "Iranian rial", "symbol": "﷼" } }, + "languages": { "fas": "Persian (Farsi)" }, + "flag": "🇮🇷" + }, + { + "cca2": "IQ", + "currencies": { "IQD": { "name": "Iraqi dinar", "symbol": "ع.د" } }, + "languages": { "ara": "Arabic", "arc": "Aramaic", "ckb": "Sorani" }, + "flag": "🇮🇶" + }, + { + "cca2": "IS", + "currencies": { "ISK": { "name": "Icelandic króna", "symbol": "kr" } }, + "languages": { "isl": "Icelandic" }, + "flag": "🇮🇸" + }, + { + "cca2": "IL", + "currencies": { "ILS": { "name": "Israeli new shekel", "symbol": "₪" } }, + "languages": { "ara": "Arabic", "heb": "Hebrew" }, + "flag": "🇮🇱" + }, + { + "cca2": "IT", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "ita": "Italian" }, + "flag": "🇮🇹" + }, + { + "cca2": "JM", + "currencies": { "JMD": { "name": "Jamaican dollar", "symbol": "$" } }, + "languages": { "eng": "English", "jam": "Jamaican Patois" }, + "flag": "🇯🇲" + }, + { + "cca2": "JE", + "currencies": { + "GBP": { "name": "British pound", "symbol": "£" }, + "JEP": { "name": "Jersey pound", "symbol": "£" } + }, + "languages": { "eng": "English", "fra": "French", "nrf": "Jèrriais" }, + "flag": "🇯🇪" + }, + { + "cca2": "JO", + "currencies": { "JOD": { "name": "Jordanian dinar", "symbol": "د.ا" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇯🇴" + }, + { + "cca2": "JP", + "currencies": { "JPY": { "name": "Japanese yen", "symbol": "¥" } }, + "languages": { "jpn": "Japanese" }, + "flag": "🇯🇵" + }, + { + "cca2": "KZ", + "currencies": { "KZT": { "name": "Kazakhstani tenge", "symbol": "₸" } }, + "languages": { "kaz": "Kazakh", "rus": "Russian" }, + "flag": "🇰🇿" + }, + { + "cca2": "KE", + "currencies": { "KES": { "name": "Kenyan shilling", "symbol": "Sh" } }, + "languages": { "eng": "English", "swa": "Swahili" }, + "flag": "🇰🇪" + }, + { + "cca2": "KG", + "currencies": { "KGS": { "name": "Kyrgyzstani som", "symbol": "с" } }, + "languages": { "kir": "Kyrgyz", "rus": "Russian" }, + "flag": "🇰🇬" + }, + { + "cca2": "KH", + "currencies": { + "KHR": { "name": "Cambodian riel", "symbol": "៛" }, + "USD": { "name": "United States dollar", "symbol": "$" } + }, + "languages": { "khm": "Khmer" }, + "flag": "🇰🇭" + }, + { + "cca2": "KI", + "currencies": { + "AUD": { "name": "Australian dollar", "symbol": "$" }, + "KID": { "name": "Kiribati dollar", "symbol": "$" } + }, + "languages": { "eng": "English", "gil": "Gilbertese" }, + "flag": "🇰🇮" + }, + { + "cca2": "KN", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇰🇳" + }, + { + "cca2": "KR", + "currencies": { "KRW": { "name": "South Korean won", "symbol": "₩" } }, + "languages": { "kor": "Korean" }, + "flag": "🇰🇷" + }, + { + "cca2": "XK", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "sqi": "Albanian", "srp": "Serbian" }, + "flag": "🇽🇰" + }, + { + "cca2": "KW", + "currencies": { "KWD": { "name": "Kuwaiti dinar", "symbol": "د.ك" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇰🇼" + }, + { + "cca2": "LA", + "currencies": { "LAK": { "name": "Lao kip", "symbol": "₭" } }, + "languages": { "lao": "Lao" }, + "flag": "🇱🇦" + }, + { + "cca2": "LB", + "currencies": { "LBP": { "name": "Lebanese pound", "symbol": "ل.ل" } }, + "languages": { "ara": "Arabic", "fra": "French" }, + "flag": "🇱🇧" + }, + { + "cca2": "LR", + "currencies": { "LRD": { "name": "Liberian dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇱🇷" + }, + { + "cca2": "LY", + "currencies": { "LYD": { "name": "Libyan dinar", "symbol": "ل.د" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇱🇾" + }, + { + "cca2": "LC", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇱🇨" + }, + { + "cca2": "LI", + "currencies": { "CHF": { "name": "Swiss franc", "symbol": "Fr" } }, + "languages": { "deu": "German" }, + "flag": "🇱🇮" + }, + { + "cca2": "LK", + "currencies": { "LKR": { "name": "Sri Lankan rupee", "symbol": "Rs රු" } }, + "languages": { "sin": "Sinhala", "tam": "Tamil" }, + "flag": "🇱🇰" + }, + { + "cca2": "LS", + "currencies": { + "LSL": { "name": "Lesotho loti", "symbol": "L" }, + "ZAR": { "name": "South African rand", "symbol": "R" } + }, + "languages": { "eng": "English", "sot": "Sotho" }, + "flag": "🇱🇸" + }, + { + "cca2": "LT", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "lit": "Lithuanian" }, + "flag": "🇱🇹" + }, + { + "cca2": "LU", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "deu": "German", "fra": "French", "ltz": "Luxembourgish" }, + "flag": "🇱🇺" + }, + { + "cca2": "LV", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "lav": "Latvian" }, + "flag": "🇱🇻" + }, + { + "cca2": "MO", + "currencies": { "MOP": { "name": "Macanese pataca", "symbol": "P" } }, + "languages": { "por": "Portuguese", "zho": "Chinese" }, + "flag": "🇲🇴" + }, + { + "cca2": "MF", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇲🇫" + }, + { + "cca2": "MA", + "currencies": { "MAD": { "name": "Moroccan dirham", "symbol": "د.م." } }, + "languages": { "ara": "Arabic", "ber": "Berber" }, + "flag": "🇲🇦" + }, + { + "cca2": "MC", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇲🇨" + }, + { + "cca2": "MD", + "currencies": { "MDL": { "name": "Moldovan leu", "symbol": "L" } }, + "languages": { "ron": "Moldavian" }, + "flag": "🇲🇩" + }, + { + "cca2": "MG", + "currencies": { "MGA": { "name": "Malagasy ariary", "symbol": "Ar" } }, + "languages": { "fra": "French", "mlg": "Malagasy" }, + "flag": "🇲🇬" + }, + { + "cca2": "MV", + "currencies": { "MVR": { "name": "Maldivian rufiyaa", "symbol": ".ރ" } }, + "languages": { "div": "Maldivian" }, + "flag": "🇲🇻" + }, + { + "cca2": "MX", + "currencies": { "MXN": { "name": "Mexican peso", "symbol": "$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇲🇽" + }, + { + "cca2": "MH", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English", "mah": "Marshallese" }, + "flag": "🇲🇭" + }, + { + "cca2": "MK", + "currencies": { "MKD": { "name": "denar", "symbol": "den" } }, + "languages": { "mkd": "Macedonian" }, + "flag": "🇲🇰" + }, + { + "cca2": "ML", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇲🇱" + }, + { + "cca2": "MT", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "eng": "English", "mlt": "Maltese" }, + "flag": "🇲🇹" + }, + { + "cca2": "MM", + "currencies": { "MMK": { "name": "Burmese kyat", "symbol": "Ks" } }, + "languages": { "mya": "Burmese" }, + "flag": "🇲🇲" + }, + { + "cca2": "ME", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "cnr": "Montenegrin" }, + "flag": "🇲🇪" + }, + { + "cca2": "MN", + "currencies": { "MNT": { "name": "Mongolian tögrög", "symbol": "₮" } }, + "languages": { "mon": "Mongolian" }, + "flag": "🇲🇳" + }, + { + "cca2": "MP", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "cal": "Carolinian", "cha": "Chamorro", "eng": "English" }, + "flag": "🇲🇵" + }, + { + "cca2": "MZ", + "currencies": { "MZN": { "name": "Mozambican metical", "symbol": "MT" } }, + "languages": { "por": "Portuguese" }, + "flag": "🇲🇿" + }, + { + "cca2": "MR", + "currencies": { "MRU": { "name": "Mauritanian ouguiya", "symbol": "UM" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇲🇷" + }, + { + "cca2": "MS", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇲🇸" + }, + { + "cca2": "MQ", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇲🇶" + }, + { + "cca2": "MU", + "currencies": { "MUR": { "name": "Mauritian rupee", "symbol": "₨" } }, + "languages": { + "eng": "English", + "fra": "French", + "mfe": "Mauritian Creole" + }, + "flag": "🇲🇺" + }, + { + "cca2": "MW", + "currencies": { "MWK": { "name": "Malawian kwacha", "symbol": "MK" } }, + "languages": { "eng": "English", "nya": "Chewa" }, + "flag": "🇲🇼" + }, + { + "cca2": "MY", + "currencies": { "MYR": { "name": "Malaysian ringgit", "symbol": "RM" } }, + "languages": { "eng": "English", "msa": "Malay" }, + "flag": "🇲🇾" + }, + { + "cca2": "YT", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇾🇹" + }, + { + "cca2": "NA", + "currencies": { + "NAD": { "name": "Namibian dollar", "symbol": "$" }, + "ZAR": { "name": "South African rand", "symbol": "R" } + }, + "languages": { + "afr": "Afrikaans", + "deu": "German", + "eng": "English", + "her": "Herero", + "hgm": "Khoekhoe", + "kwn": "Kwangali", + "loz": "Lozi", + "ndo": "Ndonga", + "tsn": "Tswana" + }, + "flag": "🇳🇦" + }, + { + "cca2": "NC", + "currencies": { "XPF": { "name": "CFP franc", "symbol": "₣" } }, + "languages": { "fra": "French" }, + "flag": "🇳🇨" + }, + { + "cca2": "NE", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇳🇪" + }, + { + "cca2": "NF", + "currencies": { "AUD": { "name": "Australian dollar", "symbol": "$" } }, + "languages": { "eng": "English", "pih": "Norfuk" }, + "flag": "🇳🇫" + }, + { + "cca2": "NG", + "currencies": { "NGN": { "name": "Nigerian naira", "symbol": "₦" } }, + "languages": { "eng": "English" }, + "flag": "🇳🇬" + }, + { + "cca2": "NI", + "currencies": { "NIO": { "name": "Nicaraguan córdoba", "symbol": "C$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇳🇮" + }, + { + "cca2": "NU", + "currencies": { "NZD": { "name": "New Zealand dollar", "symbol": "$" } }, + "languages": { "eng": "English", "niu": "Niuean" }, + "flag": "🇳🇺" + }, + { + "cca2": "NL", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "nld": "Dutch" }, + "flag": "🇳🇱" + }, + { + "cca2": "NO", + "currencies": { "NOK": { "name": "Norwegian krone", "symbol": "kr" } }, + "languages": { + "nno": "Norwegian Nynorsk", + "nob": "Norwegian Bokmål", + "smi": "Sami" + }, + "flag": "🇳🇴" + }, + { + "cca2": "NP", + "currencies": { "NPR": { "name": "Nepalese rupee", "symbol": "₨" } }, + "languages": { "nep": "Nepali" }, + "flag": "🇳🇵" + }, + { + "cca2": "NR", + "currencies": { "AUD": { "name": "Australian dollar", "symbol": "$" } }, + "languages": { "eng": "English", "nau": "Nauru" }, + "flag": "🇳🇷" + }, + { + "cca2": "NZ", + "currencies": { "NZD": { "name": "New Zealand dollar", "symbol": "$" } }, + "languages": { + "eng": "English", + "mri": "Māori", + "nzs": "New Zealand Sign Language" + }, + "flag": "🇳🇿" + }, + { + "cca2": "OM", + "currencies": { "OMR": { "name": "Omani rial", "symbol": "ر.ع." } }, + "languages": { "ara": "Arabic" }, + "flag": "🇴🇲" + }, + { + "cca2": "PK", + "currencies": { "PKR": { "name": "Pakistani rupee", "symbol": "₨" } }, + "languages": { "eng": "English", "urd": "Urdu" }, + "flag": "🇵🇰" + }, + { + "cca2": "PA", + "currencies": { + "PAB": { "name": "Panamanian balboa", "symbol": "B/." }, + "USD": { "name": "United States dollar", "symbol": "$" } + }, + "languages": { "spa": "Spanish" }, + "flag": "🇵🇦" + }, + { + "cca2": "PN", + "currencies": { "NZD": { "name": "New Zealand dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇵🇳" + }, + { + "cca2": "PE", + "currencies": { "PEN": { "name": "Peruvian sol", "symbol": "S/." } }, + "languages": { "aym": "Aymara", "que": "Quechua", "spa": "Spanish" }, + "flag": "🇵🇪" + }, + { + "cca2": "PH", + "currencies": { "PHP": { "name": "Philippine peso", "symbol": "₱" } }, + "languages": { "eng": "English", "fil": "Filipino" }, + "flag": "🇵🇭" + }, + { + "cca2": "PW", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English", "pau": "Palauan" }, + "flag": "🇵🇼" + }, + { + "cca2": "PG", + "currencies": { + "PGK": { "name": "Papua New Guinean kina", "symbol": "K" } + }, + "languages": { "eng": "English", "hmo": "Hiri Motu", "tpi": "Tok Pisin" }, + "flag": "🇵🇬" + }, + { + "cca2": "PL", + "currencies": { "PLN": { "name": "Polish złoty", "symbol": "zł" } }, + "languages": { "pol": "Polish" }, + "flag": "🇵🇱" + }, + { + "cca2": "PR", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English", "spa": "Spanish" }, + "flag": "🇵🇷" + }, + { + "cca2": "KP", + "currencies": { "KPW": { "name": "North Korean won", "symbol": "₩" } }, + "languages": { "kor": "Korean" }, + "flag": "🇰🇵" + }, + { + "cca2": "PT", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "por": "Portuguese" }, + "flag": "🇵🇹" + }, + { + "cca2": "PY", + "currencies": { "PYG": { "name": "Paraguayan guaraní", "symbol": "₲" } }, + "languages": { "grn": "Guaraní", "spa": "Spanish" }, + "flag": "🇵🇾" + }, + { + "cca2": "PS", + "currencies": { + "EGP": { "name": "Egyptian pound", "symbol": "E£" }, + "ILS": { "name": "Israeli new shekel", "symbol": "₪" }, + "JOD": { "name": "Jordanian dinar", "symbol": "JD" } + }, + "languages": { "ara": "Arabic" }, + "flag": "🇵🇸" + }, + { + "cca2": "PF", + "currencies": { "XPF": { "name": "CFP franc", "symbol": "₣" } }, + "languages": { "fra": "French" }, + "flag": "🇵🇫" + }, + { + "cca2": "QA", + "currencies": { "QAR": { "name": "Qatari riyal", "symbol": "ر.ق" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇶🇦" + }, + { + "cca2": "RE", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇷🇪" + }, + { + "cca2": "RO", + "currencies": { "RON": { "name": "Romanian leu", "symbol": "lei" } }, + "languages": { "ron": "Romanian" }, + "flag": "🇷🇴" + }, + { + "cca2": "RU", + "currencies": { "RUB": { "name": "Russian ruble", "symbol": "₽" } }, + "languages": { "rus": "Russian" }, + "flag": "🇷🇺" + }, + { + "cca2": "RW", + "currencies": { "RWF": { "name": "Rwandan franc", "symbol": "Fr" } }, + "languages": { "eng": "English", "fra": "French", "kin": "Kinyarwanda" }, + "flag": "🇷🇼" + }, + { + "cca2": "SA", + "currencies": { "SAR": { "name": "Saudi riyal", "symbol": "ر.س" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇸🇦" + }, + { + "cca2": "SD", + "currencies": { "SDG": { "name": "Sudanese pound", "symbol": "" } }, + "languages": { "ara": "Arabic", "eng": "English" }, + "flag": "🇸🇩" + }, + { + "cca2": "SN", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇸🇳" + }, + { + "cca2": "SG", + "currencies": { "SGD": { "name": "Singapore dollar", "symbol": "$" } }, + "languages": { + "zho": "Chinese", + "eng": "English", + "msa": "Malay", + "tam": "Tamil" + }, + "flag": "🇸🇬" + }, + { + "cca2": "GS", + "currencies": { "SHP": { "name": "Saint Helena pound", "symbol": "£" } }, + "languages": { "eng": "English" }, + "flag": "🇬🇸" + }, + { + "cca2": "SJ", + "currencies": { "NOK": { "name": "krone", "symbol": "kr" } }, + "languages": { "nor": "Norwegian" }, + "flag": "🇸🇯" + }, + { + "cca2": "SB", + "currencies": { + "SBD": { "name": "Solomon Islands dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇸🇧" + }, + { + "cca2": "SL", + "currencies": { "SLL": { "name": "Sierra Leonean leone", "symbol": "Le" } }, + "languages": { "eng": "English" }, + "flag": "🇸🇱" + }, + { + "cca2": "SV", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇸🇻" + }, + { + "cca2": "SM", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "ita": "Italian" }, + "flag": "🇸🇲" + }, + { + "cca2": "SO", + "currencies": { "SOS": { "name": "Somali shilling", "symbol": "Sh" } }, + "languages": { "ara": "Arabic", "som": "Somali" }, + "flag": "🇸🇴" + }, + { + "cca2": "PM", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "fra": "French" }, + "flag": "🇵🇲" + }, + { + "cca2": "RS", + "currencies": { "RSD": { "name": "Serbian dinar", "symbol": "дин." } }, + "languages": { "srp": "Serbian" }, + "flag": "🇷🇸" + }, + { + "cca2": "SS", + "currencies": { "SSP": { "name": "South Sudanese pound", "symbol": "£" } }, + "languages": { "eng": "English" }, + "flag": "🇸🇸" + }, + { + "cca2": "ST", + "currencies": { + "STN": { "name": "São Tomé and Príncipe dobra", "symbol": "Db" } + }, + "languages": { "por": "Portuguese" }, + "flag": "🇸🇹" + }, + { + "cca2": "SR", + "currencies": { "SRD": { "name": "Surinamese dollar", "symbol": "$" } }, + "languages": { "nld": "Dutch" }, + "flag": "🇸🇷" + }, + { + "cca2": "SK", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "slk": "Slovak" }, + "flag": "🇸🇰" + }, + { + "cca2": "SI", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "slv": "Slovene" }, + "flag": "🇸🇮" + }, + { + "cca2": "SE", + "currencies": { "SEK": { "name": "Swedish krona", "symbol": "kr" } }, + "languages": { "swe": "Swedish" }, + "flag": "🇸🇪" + }, + { + "cca2": "SZ", + "currencies": { + "SZL": { "name": "Swazi lilangeni", "symbol": "L" }, + "ZAR": { "name": "South African rand", "symbol": "R" } + }, + "languages": { "eng": "English", "ssw": "Swazi" }, + "flag": "🇸🇿" + }, + { + "cca2": "SX", + "currencies": { + "ANG": { "name": "Netherlands Antillean guilder", "symbol": "ƒ" } + }, + "languages": { "eng": "English", "fra": "French", "nld": "Dutch" }, + "flag": "🇸🇽" + }, + { + "cca2": "SC", + "currencies": { "SCR": { "name": "Seychellois rupee", "symbol": "₨" } }, + "languages": { + "crs": "Seychellois Creole", + "eng": "English", + "fra": "French" + }, + "flag": "🇸🇨" + }, + { + "cca2": "SY", + "currencies": { "SYP": { "name": "Syrian pound", "symbol": "£" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇸🇾" + }, + { + "cca2": "TC", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇹🇨" + }, + { + "cca2": "TD", + "currencies": { + "XAF": { "name": "Central African CFA franc", "symbol": "Fr" } + }, + "languages": { "ara": "Arabic", "fra": "French" }, + "flag": "🇹🇩" + }, + { + "cca2": "TG", + "currencies": { + "XOF": { "name": "West African CFA franc", "symbol": "Fr" } + }, + "languages": { "fra": "French" }, + "flag": "🇹🇬" + }, + { + "cca2": "TH", + "currencies": { "THB": { "name": "Thai baht", "symbol": "฿" } }, + "languages": { "tha": "Thai" }, + "flag": "🇹🇭" + }, + { + "cca2": "TJ", + "currencies": { "TJS": { "name": "Tajikistani somoni", "symbol": "ЅМ" } }, + "languages": { "rus": "Russian", "tgk": "Tajik" }, + "flag": "🇹🇯" + }, + { + "cca2": "TK", + "currencies": { "NZD": { "name": "New Zealand dollar", "symbol": "$" } }, + "languages": { "eng": "English", "smo": "Samoan", "tkl": "Tokelauan" }, + "flag": "🇹🇰" + }, + { + "cca2": "TM", + "currencies": { "TMT": { "name": "Turkmenistan manat", "symbol": "m" } }, + "languages": { "rus": "Russian", "tuk": "Turkmen" }, + "flag": "🇹🇲" + }, + { + "cca2": "TL", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "por": "Portuguese", "tet": "Tetum" }, + "flag": "🇹🇱" + }, + { + "cca2": "TO", + "currencies": { "TOP": { "name": "Tongan paʻanga", "symbol": "T$" } }, + "languages": { "eng": "English", "ton": "Tongan" }, + "flag": "🇹🇴" + }, + { + "cca2": "TT", + "currencies": { + "TTD": { "name": "Trinidad and Tobago dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇹🇹" + }, + { + "cca2": "TN", + "currencies": { "TND": { "name": "Tunisian dinar", "symbol": "د.ت" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇹🇳" + }, + { + "cca2": "TR", + "currencies": { "TRY": { "name": "Turkish lira", "symbol": "₺" } }, + "languages": { "tur": "Turkish" }, + "flag": "🇹🇷" + }, + { + "cca2": "TV", + "currencies": { + "AUD": { "name": "Australian dollar", "symbol": "$" }, + "TVD": { "name": "Tuvaluan dollar", "symbol": "$" } + }, + "languages": { "eng": "English", "tvl": "Tuvaluan" }, + "flag": "🇹🇻" + }, + { + "cca2": "TW", + "currencies": { "TWD": { "name": "New Taiwan dollar", "symbol": "$" } }, + "languages": { "zho": "Chinese" }, + "flag": "🇹🇼" + }, + { + "cca2": "TZ", + "currencies": { "TZS": { "name": "Tanzanian shilling", "symbol": "Sh" } }, + "languages": { "eng": "English", "swa": "Swahili" }, + "flag": "🇹🇿" + }, + { + "cca2": "UG", + "currencies": { "UGX": { "name": "Ugandan shilling", "symbol": "Sh" } }, + "languages": { "eng": "English", "swa": "Swahili" }, + "flag": "🇺🇬" + }, + { + "cca2": "UA", + "currencies": { "UAH": { "name": "Ukrainian hryvnia", "symbol": "₴" } }, + "languages": { "ukr": "Ukrainian" }, + "flag": "🇺🇦" + }, + { + "cca2": "UM", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇺🇲" + }, + { + "cca2": "UY", + "currencies": { "UYU": { "name": "Uruguayan peso", "symbol": "$" } }, + "languages": { "spa": "Spanish" }, + "flag": "🇺🇾" + }, + { + "cca2": "US", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇺🇸" + }, + { + "cca2": "UZ", + "currencies": { "UZS": { "name": "Uzbekistani soʻm", "symbol": "so'm" } }, + "languages": { "rus": "Russian", "uzb": "Uzbek" }, + "flag": "🇺🇿" + }, + { + "cca2": "VA", + "currencies": { "EUR": { "name": "Euro", "symbol": "€" } }, + "languages": { "ita": "Italian", "lat": "Latin" }, + "flag": "🇻🇦" + }, + { + "cca2": "VC", + "currencies": { + "XCD": { "name": "Eastern Caribbean dollar", "symbol": "$" } + }, + "languages": { "eng": "English" }, + "flag": "🇻🇨" + }, + { + "cca2": "VE", + "currencies": { + "VES": { "name": "Venezuelan bolívar soberano", "symbol": "Bs.S." } + }, + "languages": { "spa": "Spanish" }, + "flag": "🇻🇪" + }, + { + "cca2": "VG", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇻🇬" + }, + { + "cca2": "VI", + "currencies": { "USD": { "name": "United States dollar", "symbol": "$" } }, + "languages": { "eng": "English" }, + "flag": "🇻🇮" + }, + { + "cca2": "VN", + "currencies": { "VND": { "name": "Vietnamese đồng", "symbol": "₫" } }, + "languages": { "vie": "Vietnamese" }, + "flag": "🇻🇳" + }, + { + "cca2": "VU", + "currencies": { "VUV": { "name": "Vanuatu vatu", "symbol": "Vt" } }, + "languages": { "bis": "Bislama", "eng": "English", "fra": "French" }, + "flag": "🇻🇺" + }, + { + "cca2": "WF", + "currencies": { "XPF": { "name": "CFP franc", "symbol": "₣" } }, + "languages": { "fra": "French" }, + "flag": "🇼🇫" + }, + { + "cca2": "WS", + "currencies": { "WST": { "name": "Samoan tālā", "symbol": "T" } }, + "languages": { "eng": "English", "smo": "Samoan" }, + "flag": "🇼🇸" + }, + { + "cca2": "YE", + "currencies": { "YER": { "name": "Yemeni rial", "symbol": "﷼" } }, + "languages": { "ara": "Arabic" }, + "flag": "🇾🇪" + }, + { + "cca2": "ZA", + "currencies": { "ZAR": { "name": "South African rand", "symbol": "R" } }, + "languages": { + "afr": "Afrikaans", + "eng": "English", + "nbl": "Southern Ndebele", + "nso": "Northern Sotho", + "sot": "Southern Sotho", + "ssw": "Swazi", + "tsn": "Tswana", + "tso": "Tsonga", + "ven": "Venda", + "xho": "Xhosa", + "zul": "Zulu" + }, + "flag": "🇿🇦" + }, + { + "cca2": "ZM", + "currencies": { "ZMW": { "name": "Zambian kwacha", "symbol": "ZK" } }, + "languages": { "eng": "English" }, + "flag": "🇿🇲" + }, + { + "cca2": "ZW", + "currencies": { + "BWP": { "name": "Botswana pula", "symbol": "P" }, + "CNY": { "name": "Chinese yuan", "symbol": "¥" }, + "EUR": { "name": "Euro", "symbol": "€" }, + "GBP": { "name": "British pound", "symbol": "£" }, + "INR": { "name": "Indian rupee", "symbol": "₹" }, + "JPY": { "name": "Japanese yen", "symbol": "¥" }, + "USD": { "name": "United States dollar", "symbol": "$" }, + "ZAR": { "name": "South African rand", "symbol": "Rs" }, + "ZWB": { "name": "Zimbabwean bonds", "symbol": "$" } + }, + "languages": { + "bwg": "Chibarwe", + "eng": "English", + "kck": "Kalanga", + "khi": "Khoisan", + "ndc": "Ndau", + "nde": "Northern Ndebele", + "nya": "Chewa", + "sna": "Shona", + "sot": "Sotho", + "toi": "Tonga", + "tsn": "Tswana", + "tso": "Tsonga", + "ven": "Venda", + "xho": "Xhosa", + "zib": "Zimbabwean Sign Language" + }, + "flag": "🇿🇼" + } +] diff --git a/edge-functions/geolocation/pages/index.tsx b/edge-functions/geolocation/pages/index.tsx index 2da9f2adeb..59b7188422 100644 --- a/edge-functions/geolocation/pages/index.tsx +++ b/edge-functions/geolocation/pages/index.tsx @@ -62,7 +62,7 @@ export default function Index({
- {`${country} ({ + const data = countriesData.map((x) => ({ cca2: x.cca2, currencies: x.currencies, languages: x.languages, @@ -21,14 +22,14 @@ async function setupCountryInfo() { } function withCountryInfo(nextConfig = {}) { - const { rewrites } = nextConfig - // Not really adding rewrites but using its async behavior to load the country data - nextConfig.rewrites = async (...args) => { - await setupCountryInfo() - return rewrites?.(...args) ?? {} - } - - return nextConfig + const { rewrites } = nextConfig + // Not really adding rewrites but using its async behavior to load the country data + nextConfig.rewrites = async (...args) => { + await setupCountryInfo() + return rewrites?.(...args) ?? {} } -module.exports = { withCountryInfo, setupCountryInfo } \ No newline at end of file + return nextConfig +} + +module.exports = { withCountryInfo, setupCountryInfo } diff --git a/edge-functions/hostname-rewrites/README.md b/edge-functions/hostname-rewrites/README.md index d0d835f090..ab21bf7272 100644 --- a/edge-functions/hostname-rewrites/README.md +++ b/edge-functions/hostname-rewrites/README.md @@ -32,6 +32,7 @@ To give a bit of context of how this can be applied in a real-world context, we - [app.vercel.pub](https://app.vercel.pub) (editing backend) For more info on the Platforms Starter Kit: + - [Twitter Announcement](https://twitter.com/vercel/status/1484237805941403655) - [Github Repo](https://github.com/vercel/platforms) - [Official Guide](https://vercel.com/guides/nextjs-multi-tenant-application) diff --git a/edge-functions/hostname-rewrites/pages/_app.tsx b/edge-functions/hostname-rewrites/pages/_app.tsx index 62b702ae86..fccfe2368a 100644 --- a/edge-functions/hostname-rewrites/pages/_app.tsx +++ b/edge-functions/hostname-rewrites/pages/_app.tsx @@ -7,7 +7,10 @@ export default function MyApp({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/edge-functions/hostname-rewrites/pages/_sites/[site]/about.tsx b/edge-functions/hostname-rewrites/pages/_sites/[site]/about.tsx index e41693acf1..55eabdc3e7 100644 --- a/edge-functions/hostname-rewrites/pages/_sites/[site]/about.tsx +++ b/edge-functions/hostname-rewrites/pages/_sites/[site]/about.tsx @@ -3,18 +3,17 @@ import { useRouter } from 'next/router' import { Layout, Page, Text, Link } from '@vercel/examples-ui' export default function About(props) { - const router = useRouter() - if (router.isFallback) { - return ( - - - Loading... - - - ) - } - + if (router.isFallback) { + return ( + + + Loading... + + + ) + } + return ( diff --git a/edge-functions/hostname-rewrites/pages/_sites/[site]/index.tsx b/edge-functions/hostname-rewrites/pages/_sites/[site]/index.tsx index 89b5e59007..1aebc18195 100644 --- a/edge-functions/hostname-rewrites/pages/_sites/[site]/index.tsx +++ b/edge-functions/hostname-rewrites/pages/_sites/[site]/index.tsx @@ -3,18 +3,17 @@ import { useRouter } from 'next/router' import { Layout, Page, Text, Link, List } from '@vercel/examples-ui' export default function Index(props) { - const router = useRouter() - if (router.isFallback) { - return ( - - - Loading... - - - ) - } - + if (router.isFallback) { + return ( + + + Loading... + + + ) + } + return ( diff --git a/edge-functions/i18n/constants.ts b/edge-functions/i18n/constants.ts index 4c354b7407..9b6c3d0e3e 100644 --- a/edge-functions/i18n/constants.ts +++ b/edge-functions/i18n/constants.ts @@ -1,34 +1,35 @@ -import { Dictionary } from "./types"; +import { Dictionary } from './types' export const DICTIONARIES: Record = { - 'default': { + default: { title: 'i18n Example', - greet: 'Hello!, we could not detect your locale so we defaulted to english.', + greet: + 'Hello!, we could not detect your locale so we defaulted to english.', subtitle: 'Localized text based on geolocation headers', - link: 'See headers documentation' + link: 'See headers documentation', }, - 'en': { + en: { title: 'i18n Example', greet: 'Hello!', subtitle: 'Localized text based on geolocation headers', - link: 'See headers documentation' + link: 'See headers documentation', }, - 'es': { + es: { title: 'Ejemplo de i18n', greet: '¡Hola!', subtitle: 'Texto localizado basado en las cabeceras de geolocalización', - link: 'Ver la documentación de las cabeceras' + link: 'Ver la documentación de las cabeceras', }, - 'fr': { + fr: { title: 'Exemple i18n', greet: 'Bonjour!', subtitle: 'Texte localisé basé sur les en-têtes de géolocalisation', - link: 'Voir la documentation des en-têtes' + link: 'Voir la documentation des en-têtes', }, - 'cn': { + cn: { title: 'i18n 示例', greet: '你好!', subtitle: '基于地理位置标题的本地化文本', - link: '请参阅标题文档' + link: '请参阅标题文档', }, } diff --git a/edge-functions/i18n/tsconfig.json b/edge-functions/i18n/tsconfig.json index 5bee8c4d57..b8d597880a 100644 --- a/edge-functions/i18n/tsconfig.json +++ b/edge-functions/i18n/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, @@ -19,12 +15,6 @@ "jsx": "preserve", "incremental": true }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx" - ], - "exclude": [ - "node_modules" - ] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] } diff --git a/edge-functions/i18n/types.ts b/edge-functions/i18n/types.ts index a86273e150..84cc9593ef 100644 --- a/edge-functions/i18n/types.ts +++ b/edge-functions/i18n/types.ts @@ -1,6 +1,6 @@ export interface Dictionary { - title: string; - subtitle: string; - link: string; - greet: string; -} \ No newline at end of file + title: string + subtitle: string + link: string + greet: string +} diff --git a/edge-functions/image-response/lib/parse.ts b/edge-functions/image-response/lib/parse.ts index fbba74a119..f1a4c604b8 100644 --- a/edge-functions/image-response/lib/parse.ts +++ b/edge-functions/image-response/lib/parse.ts @@ -1,19 +1,19 @@ -export function b64toBlob(b64Data, contentType = "", sliceSize = 512) { - const byteCharacters = atob(b64Data); - const byteArrays = []; +export function b64toBlob(b64Data, contentType = '', sliceSize = 512) { + const byteCharacters = atob(b64Data) + const byteArrays = [] for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { - const slice = byteCharacters.slice(offset, offset + sliceSize); + const slice = byteCharacters.slice(offset, offset + sliceSize) - const byteNumbers = new Array(slice.length); + const byteNumbers = new Array(slice.length) for (let i = 0; i < slice.length; i++) { - byteNumbers[i] = slice.charCodeAt(i); + byteNumbers[i] = slice.charCodeAt(i) } - const byteArray = new Uint8Array(byteNumbers); - byteArrays.push(byteArray); + const byteArray = new Uint8Array(byteNumbers) + byteArrays.push(byteArray) } - const blob = new Blob(byteArrays, { type: contentType }); - return blob; -}; \ No newline at end of file + const blob = new Blob(byteArrays, { type: contentType }) + return blob +} diff --git a/edge-functions/image-response/pages/_middleware.ts b/edge-functions/image-response/pages/_middleware.ts index 803407bff8..85af14d7bb 100644 --- a/edge-functions/image-response/pages/_middleware.ts +++ b/edge-functions/image-response/pages/_middleware.ts @@ -1,10 +1,11 @@ import type { NextRequest } from 'next/server' -import { b64toBlob } from "../lib/parse"; +import { b64toBlob } from '../lib/parse' export default function middleware(req: NextRequest) { - const png = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABXCAYAAADyDOBXAAAAAXNSR0IArs4c6QAAB9BJREFUeF7tnXfItlMcxz92RCQjhGyyt4xshaxssjeRrHiz95aM7JG9FeIle+8RsqOIEKVe2fTN+eru9lzPucc1zrmf6/7nfZ/7usd1zvf6/b6fc65zfvdU5P2YFvgD2BX4HbgT8HNZtmyqLM/635PWuf8dzv9z4FdgiYzb81+jcm3DdCEqjgTOD404DLgE8LHs2pZrhEwN/AXMCXwKzBJ6/gdgUeDHrgjKRphcBbFPXAnsH3xEna7nFSGKlCy9JEdBpgH+BFYE3gg+Yj9xe5YB3gP82jZCKuwBp6vHgQ1CdCga9BBx6f8PA5u1glSoQvhop6Ftgbu7xPC3K3oUGVsAD+aWunJKWU5L6uwPgUWCsStiOh8yez33AbBUONCJyNVfNkN8Q06CGGWPBc4KyKvnxnpokKhjRwAX5YTBuQhi35gH+ASYqcPMxxJEA0a17acQSd+HqFH0JP3IRRB7x3XAXgXe0d3RNvgrgINy8ZIcBDG6rga8HImMblEcKULkt3KgrhwEcbp6BlgnjEEkUi8PR4kQeaMc0lbqgjhV7QTc1mOq6hbKGCxUvjf11JWyIEbV6YGPgAULMDcWKcZgwYBmg/V3shicsiDG3BOBUyKYGxPFGCxkPidlDE5VEPvG/MDHwAx9mnmRuU8Js8HfpOonqQpi77g53A20OcciYbzj/gyh8z6pekmKghhz1wSeH9A3ioQxBguhX00Rg1MUxOnqRWCNPjE3FkEmLiH0uimmrdQEcaraHbhxQMyNieLUJZS+I7XUlZIgRtEZg5HPV3K6slDGYC2MWDzQWzIYnJIgxtzTgOOHxNxYlBiDhdT6vmQWRaQiiH1joTAIVOqyAcc6d5Dj/uxfgMWAL1Pxk1QEsXcop+9QkXcUzQbfBMizklgUkYIgxlxRz1MV+UZRFNlPhNiiusYXRaQgiA1V44JVSsbcWDozBr8ArJVC2mpaEKcJjZyvqSlVFaWu3QDNDDSaupoUxJExc7gtO3fN6aobg2XsMngZfWMY3KQgRk3Nvh5TMebGUpcxWAgsFG4Mg5sSxJirK1LLdfR3lZgbE8TfLWE0WNSg0ecYe2+px5sSxDSjO3jbNOQdRV4i9Na0SiNe0oQgbqjucT9WM1XFrmZjsBBcE5C1Y3ATgrhTtApk+cQEMQYLwTVFX7u51y2Io0PrpC5PJFUVpS6huG5m1Zq66hTEV9usAXPnaAhze01bus2rzT+67VtbpNQpiFFSa20PbxhzY6IYg4XkWhhRGwbXJYjNUavR3w+90STmxgTxucnktXRIS4hqweC6BdF+jc0T9Y4iLxGaa5FdLcRVhyA2Re1oeigxqopFijFYiK7lqJUbfNWCdJrhu8DSmQliDBaia8F25eZetSA2Q+2KvTiTVFWUug4EtOu30iipUhBfTbOHveSzNTxfFUtPsZtY2vSjbXTaBFRZpFQpiK+kS4FDEsfcmFjG4AsBVY6oDIOrEsREsizwTqy1GRzvRHShu2eoS98iV7Ugk4FNMvWOIi95ANiyKgyuQhCnqq2A+zOjqliwmro2BR6pwuDLFsRmp38V1rrZY5aPNTaH4xZECK90rEepBl+2IDa7o4DzMjfyogvEa4MrKQVVpiCe65krzP2oZFLK81WDRqTbpBJQwuBSS0GVKYi94ypgvxEx8iLRjMFC+kPL9JKyBDHmrgS8PqKRUSSOvESeUsrkY1mCOF09Aaw/YmQV8xLRlqgrGUGcqrYD7hrxVNUtjqlL4xKNT4ae5xo2Qox8ujq0l3zhEcPcmPEb6VUuaskyMHhYQYy5xwFnjijmxkSxwWuOS3NdQ81zDSNIvyWTYg3L9XhnKSgtivhumNu9wwjifHk9sOcE846ieS4h/wHDeMmggpgoVgdemmCYWxTJjhSh/5uDUteggjhdPQusPUEwN5ZSPaUi9N9w0LQ1iCBOVTsDt07wVFWUujQEuGeQ1NWvIMZclUxSUZgFJhjmxqLEGKzy51rPpXFKX7PB/QpipDsJOHmCYm5MFGOwhgJn94vB/QhSdsmkWMNyPW5z/zmsDf66Hz/pRxB7xy3ALq13jHu92OA1JNi7Hy/pVRBjrrYOP9f6Rk/B60jR0OCVXjG4V0FsTFWUTOqpdRm+aKBSUL0I4lS1B3BDm6r6ujScujREuL2X1BUTxJGhkklakj9vm676EsQY/EXYAy8CGxeDY4IYc88AJrWY25cYfrExWEOFU2MYPJ4gdZdMGqi1GbzJ5q5fkdNs8LiloMYTxN6h3wbcvvWOoaS3l6iWimqqFN5ZLBLEmLse8GTrG0OJ4TfbTzR0UPWhMe/BFwli43kNWLmdzS1FEGOwhg6qzzXmnsWxBHE47Qtc3aaqUsTwhzh1qYKdKtn9L3V1C+LIUMkkzVhqFeIorc0ttXcH+DD35VfB4P9XCqpbEGPuucDRLeYO0OXxtxiDTwdO6MbgTkGc07RiXSvXHS2xsUr8FNpXdPbAuKWgOjvbrn8fsHXrHZVeRfYSDSl27PQSC2Jz2Rh4tKWqSsXoxmANLZ42Bneno7eB5VpBahHEGKyhxaq2CAliIz8YuKxNVbWI0Y3BGmJcKy0cISqZ9BmgPeUt5tanifv627AueooFuSD8TKmRrL5Tar/Jfa6fk50kQVYAlMdEWaO4BS11yd3nvwErSZCJtMkmVXFs8JP/AasBB14bEJZnAAAAAElFTkSuQmCC"; - const blob = b64toBlob(png, "image/png"); - - return new Response(blob); + const png = + 'iVBORw0KGgoAAAANSUhEUgAAAGQAAABXCAYAAADyDOBXAAAAAXNSR0IArs4c6QAAB9BJREFUeF7tnXfItlMcxz92RCQjhGyyt4xshaxssjeRrHiz95aM7JG9FeIle+8RsqOIEKVe2fTN+eru9lzPucc1zrmf6/7nfZ/7usd1zvf6/b6fc65zfvdU5P2YFvgD2BX4HbgT8HNZtmyqLM/635PWuf8dzv9z4FdgiYzb81+jcm3DdCEqjgTOD404DLgE8LHs2pZrhEwN/AXMCXwKzBJ6/gdgUeDHrgjKRphcBbFPXAnsH3xEna7nFSGKlCy9JEdBpgH+BFYE3gg+Yj9xe5YB3gP82jZCKuwBp6vHgQ1CdCga9BBx6f8PA5u1glSoQvhop6Ftgbu7xPC3K3oUGVsAD+aWunJKWU5L6uwPgUWCsStiOh8yez33AbBUONCJyNVfNkN8Q06CGGWPBc4KyKvnxnpokKhjRwAX5YTBuQhi35gH+ASYqcPMxxJEA0a17acQSd+HqFH0JP3IRRB7x3XAXgXe0d3RNvgrgINy8ZIcBDG6rga8HImMblEcKULkt3KgrhwEcbp6BlgnjEEkUi8PR4kQeaMc0lbqgjhV7QTc1mOq6hbKGCxUvjf11JWyIEbV6YGPgAULMDcWKcZgwYBmg/V3shicsiDG3BOBUyKYGxPFGCxkPidlDE5VEPvG/MDHwAx9mnmRuU8Js8HfpOonqQpi77g53A20OcciYbzj/gyh8z6pekmKghhz1wSeH9A3ioQxBguhX00Rg1MUxOnqRWCNPjE3FkEmLiH0uimmrdQEcaraHbhxQMyNieLUJZS+I7XUlZIgRtEZg5HPV3K6slDGYC2MWDzQWzIYnJIgxtzTgOOHxNxYlBiDhdT6vmQWRaQiiH1joTAIVOqyAcc6d5Dj/uxfgMWAL1Pxk1QEsXcop+9QkXcUzQbfBMizklgUkYIgxlxRz1MV+UZRFNlPhNiiusYXRaQgiA1V44JVSsbcWDozBr8ArJVC2mpaEKcJjZyvqSlVFaWu3QDNDDSaupoUxJExc7gtO3fN6aobg2XsMngZfWMY3KQgRk3Nvh5TMebGUpcxWAgsFG4Mg5sSxJirK1LLdfR3lZgbE8TfLWE0WNSg0ecYe2+px5sSxDSjO3jbNOQdRV4i9Na0SiNe0oQgbqjucT9WM1XFrmZjsBBcE5C1Y3ATgrhTtApk+cQEMQYLwTVFX7u51y2Io0PrpC5PJFUVpS6huG5m1Zq66hTEV9usAXPnaAhze01bus2rzT+67VtbpNQpiFFSa20PbxhzY6IYg4XkWhhRGwbXJYjNUavR3w+90STmxgTxucnktXRIS4hqweC6BdF+jc0T9Y4iLxGaa5FdLcRVhyA2Re1oeigxqopFijFYiK7lqJUbfNWCdJrhu8DSmQliDBaia8F25eZetSA2Q+2KvTiTVFWUug4EtOu30iipUhBfTbOHveSzNTxfFUtPsZtY2vSjbXTaBFRZpFQpiK+kS4FDEsfcmFjG4AsBVY6oDIOrEsREsizwTqy1GRzvRHShu2eoS98iV7Ugk4FNMvWOIi95ANiyKgyuQhCnqq2A+zOjqliwmro2BR6pwuDLFsRmp38V1rrZY5aPNTaH4xZECK90rEepBl+2IDa7o4DzMjfyogvEa4MrKQVVpiCe65krzP2oZFLK81WDRqTbpBJQwuBSS0GVKYi94ypgvxEx8iLRjMFC+kPL9JKyBDHmrgS8PqKRUSSOvESeUsrkY1mCOF09Aaw/YmQV8xLRlqgrGUGcqrYD7hrxVNUtjqlL4xKNT4ae5xo2Qox8ujq0l3zhEcPcmPEb6VUuaskyMHhYQYy5xwFnjijmxkSxwWuOS3NdQ81zDSNIvyWTYg3L9XhnKSgtivhumNu9wwjifHk9sOcE846ieS4h/wHDeMmggpgoVgdemmCYWxTJjhSh/5uDUteggjhdPQusPUEwN5ZSPaUi9N9w0LQ1iCBOVTsDt07wVFWUujQEuGeQ1NWvIMZclUxSUZgFJhjmxqLEGKzy51rPpXFKX7PB/QpipDsJOHmCYm5MFGOwhgJn94vB/QhSdsmkWMNyPW5z/zmsDf66Hz/pRxB7xy3ALq13jHu92OA1JNi7Hy/pVRBjrrYOP9f6Rk/B60jR0OCVXjG4V0FsTFWUTOqpdRm+aKBSUL0I4lS1B3BDm6r6ujScujREuL2X1BUTxJGhkklakj9vm676EsQY/EXYAy8CGxeDY4IYc88AJrWY25cYfrExWEOFU2MYPJ4gdZdMGqi1GbzJ5q5fkdNs8LiloMYTxN6h3wbcvvWOoaS3l6iWimqqFN5ZLBLEmLse8GTrG0OJ4TfbTzR0UPWhMe/BFwli43kNWLmdzS1FEGOwhg6qzzXmnsWxBHE47Qtc3aaqUsTwhzh1qYKdKtn9L3V1C+LIUMkkzVhqFeIorc0ttXcH+DD35VfB4P9XCqpbEGPuucDRLeYO0OXxtxiDTwdO6MbgTkGc07RiXSvXHS2xsUr8FNpXdPbAuKWgOjvbrn8fsHXrHZVeRfYSDSl27PQSC2Jz2Rh4tKWqSsXoxmANLZ42Bneno7eB5VpBahHEGKyhxaq2CAliIz8YuKxNVbWI0Y3BGmJcKy0cISqZ9BmgPeUt5tanifv627AueooFuSD8TKmRrL5Tar/Jfa6fk50kQVYAlMdEWaO4BS11yd3nvwErSZCJtMkmVXFs8JP/AasBB14bEJZnAAAAAElFTkSuQmCC' + const blob = b64toBlob(png, 'image/png') + + return new Response(blob) } diff --git a/edge-functions/jwt-authentication/pages/api/index.ts b/edge-functions/jwt-authentication/pages/api/index.ts index 8f255e2519..c630f34818 100644 --- a/edge-functions/jwt-authentication/pages/api/index.ts +++ b/edge-functions/jwt-authentication/pages/api/index.ts @@ -14,7 +14,10 @@ export default async function handler( } try { const token = req.cookies[USER_TOKEN] - const { payload } = await jwtVerify(token, new TextEncoder().encode(JWT_SECRET_KEY)) + const { payload } = await jwtVerify( + token, + new TextEncoder().encode(JWT_SECRET_KEY) + ) res.status(200).json({ nanoid: nanoid(), jwtID: payload.jti }) } catch (err) { res.status(401).json({ error: { message: 'Your token has expired.' } }) diff --git a/edge-functions/logging/pages/_middleware.ts b/edge-functions/logging/pages/_middleware.ts index 1cbeec0edf..7560f82111 100644 --- a/edge-functions/logging/pages/_middleware.ts +++ b/edge-functions/logging/pages/_middleware.ts @@ -11,8 +11,8 @@ export default function middleware(req: NextRequest) { fetch('https://in.logtail.com', { method: 'POST', headers: { - "Content-Type": "application/json", - "Authorization": `Bearer ${process.env.LOGTAIL_TOKEN}` + 'Content-Type': 'application/json', + Authorization: `Bearer ${process.env.LOGTAIL_TOKEN}`, }, body: JSON.stringify({ message: 'Log from the edge', @@ -20,9 +20,9 @@ export default function middleware(req: NextRequest) { page: req.nextUrl.href, referrer: req.referrer, ua: req.ua?.ua, - geo: req.geo - } - }) + geo: req.geo, + }, + }), }) } } diff --git a/edge-functions/logging/pages/index.tsx b/edge-functions/logging/pages/index.tsx index fc53d47377..c7c226e51b 100644 --- a/edge-functions/logging/pages/index.tsx +++ b/edge-functions/logging/pages/index.tsx @@ -1,17 +1,17 @@ -import { FC } from "react"; -import Image from "next/image"; -import Head from "next/head"; -import { Layout, Text, Page, Link, Code } from "@vercel/examples-ui"; +import { FC } from 'react' +import Image from 'next/image' +import Head from 'next/head' +import { Layout, Text, Page, Link, Code } from '@vercel/examples-ui' -import board from "../public/board.jpg"; +import board from '../public/board.jpg' const Snippet: FC = ({ children }) => { return (
       {children}
     
- ); -}; + ) +} function Home() { return ( @@ -67,18 +67,18 @@ export default function middleware(req) { This way our call will not block the execution (because we do not want to block the request until completion as we do not need the response) while logging the information in our service of choice. This example - uses{" "} + uses{' '} Logtail - {" "} + {' '} but you can use whatever service you like as soon as it has a rest-based approach or an edge compatible SDK.
- ); + ) } -Home.Layout = Layout; +Home.Layout = Layout -export default Home; +export default Home diff --git a/edge-functions/next-news/components/comment-form.tsx b/edge-functions/next-news/components/comment-form.tsx index f9c26e49bd..53ce5620f3 100644 --- a/edge-functions/next-news/components/comment-form.tsx +++ b/edge-functions/next-news/components/comment-form.tsx @@ -10,7 +10,7 @@ export default function CommentForm() { display: block; margin-bottom: 10px; } - + button { padding: 3px 4px; } diff --git a/edge-functions/next-news/components/comment.tsx b/edge-functions/next-news/components/comment.tsx index 99f48dbf06..aa89765dee 100644 --- a/edge-functions/next-news/components/comment.tsx +++ b/edge-functions/next-news/components/comment.tsx @@ -1,23 +1,23 @@ -import React from "react"; -import timeAgo from "../lib/time-ago"; +import React from 'react' +import timeAgo from '../lib/time-ago' export default class Comment extends React.Component { constructor(props) { - super(props); - this.state = { toggled: false }; - this.toggle = this.toggle.bind(this); + super(props) + this.state = { toggled: false } + this.toggle = this.toggle.bind(this) } render() { - const { user, text, date, comments } = this.props; + const { user, text, date, comments } = this.props return (
- {user} {timeAgo(new Date(date))} ago{" "} + {user} {timeAgo(new Date(date))} ago{' '} {this.state.toggled ? `[+${(this.props.commentsCount || 0) + 1}]` - : "[-]"} + : '[-]'}
@@ -79,10 +79,10 @@ export default class Comment extends React.Component { } `}
- ); + ) } toggle() { - this.setState({ toggled: !this.state.toggled }); + this.setState({ toggled: !this.state.toggled }) } } diff --git a/edge-functions/next-news/components/header.tsx b/edge-functions/next-news/components/header.tsx index 833025faab..58c181a7a2 100644 --- a/edge-functions/next-news/components/header.tsx +++ b/edge-functions/next-news/components/header.tsx @@ -1,6 +1,6 @@ -import Nav from "./nav"; -import Logo from "./logo"; -import Link from "next/link"; +import Nav from './nav' +import Logo from './logo' +import Link from 'next/link' export default function Header() { return ( @@ -23,28 +23,28 @@ export default function Header() { login
- + ) -}; +} diff --git a/edge-functions/next-news/components/item.tsx b/edge-functions/next-news/components/item.tsx index 500276e532..86259ca51a 100644 --- a/edge-functions/next-news/components/item.tsx +++ b/edge-functions/next-news/components/item.tsx @@ -3,7 +3,7 @@ import Story from '../components/story' import Comment from '../components/comment' import CommentForm from '../components/comment-form' -export default ({ story, comments=null }) => ( +export default ({ story, comments = null }) => (
@@ -12,13 +12,11 @@ export default ({ story, comments=null }) => (
- { - comments - ? comments.map((comment) => ( - - )) - :
Loading…
- } + {comments ? ( + comments.map((comment) => ) + ) : ( +
Loading…
+ )}
- ) -} \ No newline at end of file + ) +} diff --git a/edge-functions/next-news/components/meta.tsx b/edge-functions/next-news/components/meta.tsx index e09d1f1a20..670e48b0cc 100644 --- a/edge-functions/next-news/components/meta.tsx +++ b/edge-functions/next-news/components/meta.tsx @@ -2,9 +2,10 @@ import Head from 'next/head' import NProgress from 'nprogress' import Router from 'next/router' -(Router as any).onRouteChangeStart = () => NProgress.start() -(Router as any).onRouteChangeComplete = () => NProgress.done() -(Router as any).onRouteChangeError = () => NProgress.done() +;(Router as any).onRouteChangeStart = () => + (NProgress.start()(Router as any).onRouteChangeComplete = () => + (NProgress.done()(Router as any).onRouteChangeError = () => + NProgress.done())) export default function Meta() { return ( @@ -16,21 +17,23 @@ export default function Meta() { diff --git a/edge-functions/next-news/components/nav.tsx b/edge-functions/next-news/components/nav.tsx index 1c7c4a66b7..666daa398f 100644 --- a/edge-functions/next-news/components/nav.tsx +++ b/edge-functions/next-news/components/nav.tsx @@ -1,4 +1,4 @@ -import Link from "next/link"; +import Link from 'next/link' export default function Nav() { return ( @@ -8,7 +8,7 @@ export default function Nav() { ask jobs submit - + ) -}; +} const Item = ({ href, children }) => (
  • @@ -43,4 +43,4 @@ const Item = ({ href, children }) => ( } `}
  • -); +) diff --git a/edge-functions/next-news/components/page.tsx b/edge-functions/next-news/components/page.tsx index 61cbbc9009..823fda723b 100644 --- a/edge-functions/next-news/components/page.tsx +++ b/edge-functions/next-news/components/page.tsx @@ -6,9 +6,7 @@ export default ({ children }) => (
    -
    - { children } -
    +
    {children}

    -); +) diff --git a/edge-functions/next-news/components/story.tsx b/edge-functions/next-news/components/story.tsx index ae3e2ef440..73380c69fb 100644 --- a/edge-functions/next-news/components/story.tsx +++ b/edge-functions/next-news/components/story.tsx @@ -1,9 +1,9 @@ -import Link from "next/link"; -import timeAgo from "../lib/time-ago"; -import parse from "url-parse"; +import Link from 'next/link' +import timeAgo from '../lib/time-ago' +import parse from 'url-parse' export default ({ id, title, date, url, user, score, commentsCount }: any) => { - const { host } = parse(url); + const { host } = parse(url) return (
    @@ -16,28 +16,28 @@ export default ({ id, title, date, url, user, score, commentsCount }: any) => { )} {url && ( - {host.replace(/^www\./, "")} + {host.replace(/^www\./, '')} )}
    @@ -78,7 +78,7 @@ export default ({ id, title, date, url, user, score, commentsCount }: any) => { } `}
    - ); -}; + ) +} -const plural = (n, s) => s + (n === 0 || n > 1 ? "s" : ""); +const plural = (n, s) => s + (n === 0 || n > 1 ? 's' : '') diff --git a/edge-functions/next-news/components/updating-story.tsx b/edge-functions/next-news/components/updating-story.tsx index bdb6eb382f..85947f717a 100644 --- a/edge-functions/next-news/components/updating-story.tsx +++ b/edge-functions/next-news/components/updating-story.tsx @@ -3,23 +3,22 @@ import Story from './story' import { observe } from '../lib/get-item' export default class extends React.Component { - unsubscribe: VoidFunction; + unsubscribe: VoidFunction - constructor (props) { + constructor(props) { super(props) this.state = props } - componentDidMount () { + componentDidMount() { this.unsubscribe = observe(this.props.id, (data) => this.setState(data)) } - componentWillUnmount () { + componentWillUnmount() { this.unsubscribe() } - render () { + render() { return } - } diff --git a/edge-functions/next-news/lib/db.ts b/edge-functions/next-news/lib/db.ts index 0bc2aafc3d..e4ce0e5802 100644 --- a/edge-functions/next-news/lib/db.ts +++ b/edge-functions/next-news/lib/db.ts @@ -1,18 +1,18 @@ -import firebase from "firebase/compat/app"; -import "firebase/compat/database"; +import firebase from 'firebase/compat/app' +import 'firebase/compat/database' try { firebase.initializeApp({ - databaseURL: "https://hacker-news.firebaseio.com", - }); + databaseURL: 'https://hacker-news.firebaseio.com', + }) } catch (err) { // we skip the "already exists" message which is // not an actual error when we're hot-reloading if (!/already exists/.test(err.message)) { - console.error("Firebase initialization error", err.stack); + console.error('Firebase initialization error', err.stack) } } -const root = firebase.database().ref("v0"); +const root = firebase.database().ref('v0') -export default root; +export default root diff --git a/edge-functions/next-news/lib/get-comments.ts b/edge-functions/next-news/lib/get-comments.ts index 55ae1eb224..7ee7a2c4fb 100644 --- a/edge-functions/next-news/lib/get-comments.ts +++ b/edge-functions/next-news/lib/get-comments.ts @@ -1,19 +1,19 @@ -import db from "./db"; +import db from './db' // hydrate comments based on an array of item ids export default function fetch(ids) { return Promise.all( ids.map(async (id) => { - const item = await db.child("item").child(id).once("value"); - const val = item.val(); + const item = await db.child('item').child(id).once('value') + const val = item.val() return { id: val.id, user: val.by || null, - text: val.text || "", + text: val.text || '', date: new Date(val.time * 1000).toISOString(), comments: await fetch(val.kids || []), commentsCount: val.descendants || 0, - }; + } }) - ); + ) } diff --git a/edge-functions/next-news/lib/get-item.ts b/edge-functions/next-news/lib/get-item.ts index 5a1c0eb032..21280bcc3e 100644 --- a/edge-functions/next-news/lib/get-item.ts +++ b/edge-functions/next-news/lib/get-item.ts @@ -1,20 +1,20 @@ -import db from "./db"; +import db from './db' export default async function getItem(id) { - const item = await db.child("item").child(id).once("value"); - const val = item.val(); + const item = await db.child('item').child(id).once('value') + const val = item.val() if (val) { - return transform(val); + return transform(val) } else { - return null; + return null } } export function observe(id, fn) { - const onval = (data) => fn(transform(data.val())); - const item = db.child("item").child(id); - item.on("value", onval); - return () => item.off("value", onval); + const onval = (data) => fn(transform(data.val())) + const item = db.child('item').child(id) + item.on('value', onval) + return () => item.off('value', onval) } export function transform(val) { @@ -29,5 +29,5 @@ export function transform(val) { commentsCount: val.descendants || 0, score: val.score, title: val.title, - }; + } } diff --git a/edge-functions/next-news/lib/time-ago.ts b/edge-functions/next-news/lib/time-ago.ts index b0cda13809..9a9f22ae58 100644 --- a/edge-functions/next-news/lib/time-ago.ts +++ b/edge-functions/next-news/lib/time-ago.ts @@ -1,12 +1,12 @@ -import ms from "ms"; +import ms from 'ms' const map = { - s: "seconds", - ms: "milliseconds", - m: "minutes", - h: "hours", - d: "days", -}; + s: 'seconds', + ms: 'milliseconds', + m: 'minutes', + h: 'hours', + d: 'days', +} export default (date) => - ms(+new Date() - date).replace(/[a-z]+/, (str) => " " + map[str]); + ms(+new Date() - date).replace(/[a-z]+/, (str) => ' ' + map[str]) diff --git a/edge-functions/next-news/next.config.mjs b/edge-functions/next-news/next.config.mjs index a0c954656b..0a16483a11 100644 --- a/edge-functions/next-news/next.config.mjs +++ b/edge-functions/next-news/next.config.mjs @@ -1,4 +1,4 @@ export default { reactStrictMode: true, swcMinify: true, -}; +} diff --git a/edge-functions/next-news/pages/ask.tsx b/edge-functions/next-news/pages/ask.tsx index 4404b631d1..5f675c0de2 100644 --- a/edge-functions/next-news/pages/ask.tsx +++ b/edge-functions/next-news/pages/ask.tsx @@ -1,15 +1,15 @@ -import Page from "../components/page"; -import Stories from "../components/stories"; -import getStories from "../lib/get-stories"; +import Page from '../components/page' +import Stories from '../components/stories' +import getStories from '../lib/get-stories' export async function getStaticProps() { - const stories = await getStories("askstories"); - return { props: { stories }, revalidate: 1 }; + const stories = await getStories('askstories') + return { props: { stories }, revalidate: 1 } } export default function News({ stories }) { return ( - ); + ) } diff --git a/edge-functions/next-news/pages/home.tsx b/edge-functions/next-news/pages/home.tsx index 3c607111f1..95eaf1c49b 100644 --- a/edge-functions/next-news/pages/home.tsx +++ b/edge-functions/next-news/pages/home.tsx @@ -1,3 +1,3 @@ export default function Home() { return
    Home
    -}; +} diff --git a/edge-functions/next-news/pages/item/[id].tsx b/edge-functions/next-news/pages/item/[id].tsx index 7c671995af..2d177d19b0 100644 --- a/edge-functions/next-news/pages/item/[id].tsx +++ b/edge-functions/next-news/pages/item/[id].tsx @@ -1,43 +1,43 @@ -import Page from "../../components/page"; -import Item from "../../components/item"; -import getItem from "../../lib/get-item"; -import getComments from "../../lib/get-comments"; -import { useEffect, useState } from "react"; +import Page from '../../components/page' +import Item from '../../components/item' +import getItem from '../../lib/get-item' +import getComments from '../../lib/get-comments' +import { useEffect, useState } from 'react' export function getStaticPaths() { return { // always build a sanity check - paths: [{ params: { id: "29001721" } }], - fallback: "blocking", - }; + paths: [{ params: { id: '29001721' } }], + fallback: 'blocking', + } } export async function getStaticProps({ params: { id } }) { - const story = await getItem(id); + const story = await getItem(id) return { props: { story, id }, revalidate: 1, - }; + } } export default function ItemPage({ story }) { - console.log("story", story); - const [comments, setComments] = useState([]); + console.log('story', story) + const [comments, setComments] = useState([]) useEffect(() => { if (story) getComments(story.comments) .then((comments) => { - setComments(comments); + setComments(comments) }) .catch((err) => { // TODO: handle error - }); - }, [story]); + }) + }, [story]) return ( - ); + ) } diff --git a/edge-functions/next-news/pages/jobs.tsx b/edge-functions/next-news/pages/jobs.tsx index ef20d8f6b9..5761ad1a74 100644 --- a/edge-functions/next-news/pages/jobs.tsx +++ b/edge-functions/next-news/pages/jobs.tsx @@ -1,15 +1,15 @@ -import Page from "../components/page"; -import Stories from "../components/stories"; -import getStories from "../lib/get-stories"; +import Page from '../components/page' +import Stories from '../components/stories' +import getStories from '../lib/get-stories' export async function getStaticProps() { - const stories = await getStories("jobstories"); - return { props: { stories }, revalidate: 1 }; + const stories = await getStories('jobstories') + return { props: { stories }, revalidate: 1 } } export default function Jobs({ stories }) { return ( - ); + ) } diff --git a/edge-functions/next-news/pages/login.tsx b/edge-functions/next-news/pages/login.tsx index 7c1ad3eb48..05d658bd1f 100644 --- a/edge-functions/next-news/pages/login.tsx +++ b/edge-functions/next-news/pages/login.tsx @@ -1,9 +1,9 @@ -import LoginForm from "../components/login-form"; +import LoginForm from '../components/login-form' export default function Login() { return (
    - ); + ) } diff --git a/edge-functions/next-news/pages/newest.tsx b/edge-functions/next-news/pages/newest.tsx index a488db3443..75f2abb8e0 100644 --- a/edge-functions/next-news/pages/newest.tsx +++ b/edge-functions/next-news/pages/newest.tsx @@ -1,16 +1,16 @@ -import React from "react"; -import Page from "../components/page"; -import Stories from "../components/stories"; -import getStories from "../lib/get-stories"; +import React from 'react' +import Page from '../components/page' +import Stories from '../components/stories' +import getStories from '../lib/get-stories' export async function getStaticProps() { - const stories = await getStories("newstories"); - return { props: { stories }, revalidate: 1 }; + const stories = await getStories('newstories') + return { props: { stories }, revalidate: 1 } } export default function Newest({ stories }) { return ( - ); + ) } diff --git a/edge-functions/next-news/pages/news/[page].tsx b/edge-functions/next-news/pages/news/[page].tsx index 1f5fd618ca..c2c370999d 100644 --- a/edge-functions/next-news/pages/news/[page].tsx +++ b/edge-functions/next-news/pages/news/[page].tsx @@ -1,28 +1,28 @@ -import Page from "../../components/page"; -import Stories from "../../components/stories"; -import getStories from "../../lib/get-stories"; +import Page from '../../components/page' +import Stories from '../../components/stories' +import getStories from '../../lib/get-stories' export function getStaticPaths() { return { - paths: [{ params: { page: "1" } }, { params: { page: "2" } }], - fallback: "blocking", - }; + paths: [{ params: { page: '1' } }, { params: { page: '2' } }], + fallback: 'blocking', + } } export async function getStaticProps({ params: { page = 1 } }) { - page = Number(page); - const stories = await getStories("topstories", { page }); + page = Number(page) + const stories = await getStories('topstories', { page }) return { props: { page, stories }, revalidate: 1, - }; + } } export default function News({ page, url, stories }) { - const offset = (page - 1) * 30; + const offset = (page - 1) * 30 return ( - ); + ) } diff --git a/edge-functions/next-news/pages/show.tsx b/edge-functions/next-news/pages/show.tsx index b94246baf9..311d1065e9 100644 --- a/edge-functions/next-news/pages/show.tsx +++ b/edge-functions/next-news/pages/show.tsx @@ -1,15 +1,15 @@ -import Page from "../components/page"; -import Stories from "../components/stories"; -import getStories from "../lib/get-stories"; +import Page from '../components/page' +import Stories from '../components/stories' +import getStories from '../lib/get-stories' export async function getStaticProps() { - const stories = await getStories("showstories"); - return { props: { stories }, revalidate: 1 }; + const stories = await getStories('showstories') + return { props: { stories }, revalidate: 1 } } export default function Show({ stories }) { return ( - ); + ) } diff --git a/edge-functions/next-news/pages/submit.tsx b/edge-functions/next-news/pages/submit.tsx index 6f000ed540..bdd5f94cb8 100644 --- a/edge-functions/next-news/pages/submit.tsx +++ b/edge-functions/next-news/pages/submit.tsx @@ -1,9 +1,9 @@ -import LoginForm from "../components/login-form"; +import LoginForm from '../components/login-form' export default function Signup() { return (
    - ); + ) } diff --git a/edge-functions/next-news/pages/user.tsx b/edge-functions/next-news/pages/user.tsx index ea32de938f..af249c2d07 100644 --- a/edge-functions/next-news/pages/user.tsx +++ b/edge-functions/next-news/pages/user.tsx @@ -1,6 +1,3 @@ export default function User() { - return ( -
    user page (WIP)
    - ) + return
    user page (WIP)
    } - diff --git a/edge-functions/next-news/tsconfig.json b/edge-functions/next-news/tsconfig.json index 6db37c02f4..1563f3e878 100644 --- a/edge-functions/next-news/tsconfig.json +++ b/edge-functions/next-news/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, @@ -19,12 +15,6 @@ "isolatedModules": true, "jsx": "preserve" }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx" - ], - "exclude": [ - "node_modules" - ] + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] } diff --git a/edge-functions/personalization-builder-io/README.md b/edge-functions/personalization-builder-io/README.md index b5ca0601c1..bed1864052 100644 --- a/edge-functions/personalization-builder-io/README.md +++ b/edge-functions/personalization-builder-io/README.md @@ -2,7 +2,6 @@ This example walks you through personalizing Builder.io landing pages with Next.js. - ## Overview To use this project, you need to do three things: diff --git a/edge-functions/personalization-builder-io/next.config.js b/edge-functions/personalization-builder-io/next.config.js index d403ed814c..abbca49584 100644 --- a/edge-functions/personalization-builder-io/next.config.js +++ b/edge-functions/personalization-builder-io/next.config.js @@ -1,4 +1,3 @@ - module.exports = { images: { domains: ['cdn.builder.io'], diff --git a/edge-functions/power-parity-pricing-strategies/PPP.md b/edge-functions/power-parity-pricing-strategies/PPP.md index af8d9a9cee..a3c415fc49 100644 --- a/edge-functions/power-parity-pricing-strategies/PPP.md +++ b/edge-functions/power-parity-pricing-strategies/PPP.md @@ -1,4 +1,5 @@ # PPP calculation + For calculating the PPP we used this function: ```js @@ -6,31 +7,285 @@ let prices = {} const PRICE = 15 const COUNTRIES = [ - "af","al","dz","as","ad","ao","ai","aq","ag","ar","am","aw","au","at","az","bs","bh","bd","bb","by","be","bz","bj","bm","bt","bo","bq","ba","bw","bv","br","io","bn","bg","bf","bi","cv","kh","cm","ca","ky","cf","td","cl","cn","cx","cc","co","km","cd","cg","ck","cr","hr","cu","cw","cy","cz","ci","dk","dj","dm","do","ec","eg","sv","gq","er","ee","sz","et","fk","fo","fj","fi","fr","gf","pf","tf","ga","gm","ge","de","gh","gi","gr","gl","gd","gp","gu","gt","gg","gn","gw","gy","ht","hm","va","hn","hk","hu","is","in","id","ir","iq","ie","im","il","it","jm","jp","je","jo","kz","ke","ki","kp","kr","kw","kg","la","lv","lb","ls","lr","ly","li","lt","lu","mo","mg","mw","my","mv","ml","mt","mh","mq","mr","mu","yt","mx","fm","md","mc","mn","me","ms","ma","mz","mm","na","nr","np","nl","nc","nz","ni","ne","ng","nu","nf","mp","no","om","pk","pw","ps","pa","pg","py","pe","ph","pn","pl","pt","pr","qa","mk","ro","ru","rw","re","bl","sh","kn","lc","mf","pm","vc","ws","sm","st","sa","sn","rs","sc","sl","sg","sx","sk","si","sb","so","za","gs","ss","es","lk","sd","sr","sj","se","ch","sy","tw","tj","tz","th","tl","tg","tk","to","tt","tn","tr","tm","tc","tv","ug","ua","ae","gb","um","us","uy","uz","vu","ve","vn","vg","vi","wf","eh","ye","zm","zw","ax" + 'af', + 'al', + 'dz', + 'as', + 'ad', + 'ao', + 'ai', + 'aq', + 'ag', + 'ar', + 'am', + 'aw', + 'au', + 'at', + 'az', + 'bs', + 'bh', + 'bd', + 'bb', + 'by', + 'be', + 'bz', + 'bj', + 'bm', + 'bt', + 'bo', + 'bq', + 'ba', + 'bw', + 'bv', + 'br', + 'io', + 'bn', + 'bg', + 'bf', + 'bi', + 'cv', + 'kh', + 'cm', + 'ca', + 'ky', + 'cf', + 'td', + 'cl', + 'cn', + 'cx', + 'cc', + 'co', + 'km', + 'cd', + 'cg', + 'ck', + 'cr', + 'hr', + 'cu', + 'cw', + 'cy', + 'cz', + 'ci', + 'dk', + 'dj', + 'dm', + 'do', + 'ec', + 'eg', + 'sv', + 'gq', + 'er', + 'ee', + 'sz', + 'et', + 'fk', + 'fo', + 'fj', + 'fi', + 'fr', + 'gf', + 'pf', + 'tf', + 'ga', + 'gm', + 'ge', + 'de', + 'gh', + 'gi', + 'gr', + 'gl', + 'gd', + 'gp', + 'gu', + 'gt', + 'gg', + 'gn', + 'gw', + 'gy', + 'ht', + 'hm', + 'va', + 'hn', + 'hk', + 'hu', + 'is', + 'in', + 'id', + 'ir', + 'iq', + 'ie', + 'im', + 'il', + 'it', + 'jm', + 'jp', + 'je', + 'jo', + 'kz', + 'ke', + 'ki', + 'kp', + 'kr', + 'kw', + 'kg', + 'la', + 'lv', + 'lb', + 'ls', + 'lr', + 'ly', + 'li', + 'lt', + 'lu', + 'mo', + 'mg', + 'mw', + 'my', + 'mv', + 'ml', + 'mt', + 'mh', + 'mq', + 'mr', + 'mu', + 'yt', + 'mx', + 'fm', + 'md', + 'mc', + 'mn', + 'me', + 'ms', + 'ma', + 'mz', + 'mm', + 'na', + 'nr', + 'np', + 'nl', + 'nc', + 'nz', + 'ni', + 'ne', + 'ng', + 'nu', + 'nf', + 'mp', + 'no', + 'om', + 'pk', + 'pw', + 'ps', + 'pa', + 'pg', + 'py', + 'pe', + 'ph', + 'pn', + 'pl', + 'pt', + 'pr', + 'qa', + 'mk', + 'ro', + 'ru', + 'rw', + 're', + 'bl', + 'sh', + 'kn', + 'lc', + 'mf', + 'pm', + 'vc', + 'ws', + 'sm', + 'st', + 'sa', + 'sn', + 'rs', + 'sc', + 'sl', + 'sg', + 'sx', + 'sk', + 'si', + 'sb', + 'so', + 'za', + 'gs', + 'ss', + 'es', + 'lk', + 'sd', + 'sr', + 'sj', + 'se', + 'ch', + 'sy', + 'tw', + 'tj', + 'tz', + 'th', + 'tl', + 'tg', + 'tk', + 'to', + 'tt', + 'tn', + 'tr', + 'tm', + 'tc', + 'tv', + 'ug', + 'ua', + 'ae', + 'gb', + 'um', + 'us', + 'uy', + 'uz', + 'vu', + 've', + 'vn', + 'vg', + 'vi', + 'wf', + 'eh', + 'ye', + 'zm', + 'zw', + 'ax', ] const REGIONS = { - "1": 13, - "2": 12, - "3": 10, - "4": 9, - "5": 7.5 - } + 1: 13, + 2: 12, + 3: 10, + 4: 9, + 5: 7.5, +} for await (const country of COUNTRIES) { - let factor = 1; - + let factor = 1 + try { - factor = await fetch(`https://api.purchasing-power-parity.com/?target=${country.toUpperCase()}`) - .then(res => res.json()) - .then(({ppp: {pppConversionFactor: factor}}) => factor) + factor = await fetch( + `https://api.purchasing-power-parity.com/?target=${country.toUpperCase()}` + ) + .then((res) => res.json()) + .then(({ ppp: { pppConversionFactor: factor } }) => factor) } catch (e) { console.warn(`Failed for ${country}`) } - - prices[country] = Object.entries(REGIONS).reduce((match, item) => PRICE * factor < match[1] ? item : match, ["1", Infinity])[0] + + prices[country] = Object.entries(REGIONS).reduce( + (match, item) => (PRICE * factor < match[1] ? item : match), + ['1', Infinity] + )[0] } console.log(prices) ``` -Along with this API `https://purchasing-power-parity.com/` to determine which region is the best fit. \ No newline at end of file + +Along with this API `https://purchasing-power-parity.com/` to determine which region is the best fit. diff --git a/edge-functions/power-parity-pricing-strategies/api.ts b/edge-functions/power-parity-pricing-strategies/api.ts index e603025437..b2338fed3b 100644 --- a/edge-functions/power-parity-pricing-strategies/api.ts +++ b/edge-functions/power-parity-pricing-strategies/api.ts @@ -8,7 +8,7 @@ const PRODUCT: Product = { price: 15, image: '/mug.png', discount: REGIONS['1'].discount, - link: `${STORE_URL}/cart/${REGIONS['1'].id}:1` + link: `${STORE_URL}/cart/${REGIONS['1'].id}:1`, } export const PRODUCTS: Record = { // Afghanistan @@ -1512,7 +1512,7 @@ export const PRODUCTS: Record = { ...PRODUCT, discount: REGIONS['1'].discount, link: `${STORE_URL}/cart/${REGIONS['1'].id}:1`, - } + }, } export default { @@ -1533,6 +1533,7 @@ export default { return new Promise((resolve) => setTimeout(() => resolve(product), delay)) }, - countries: async (): Promise => Object.keys(PRODUCTS) as Country[] - } + countries: async (): Promise => + Object.keys(PRODUCTS) as Country[], + }, } diff --git a/edge-functions/power-parity-pricing-strategies/constants.ts b/edge-functions/power-parity-pricing-strategies/constants.ts index 7fb4595e85..9128378ce8 100644 --- a/edge-functions/power-parity-pricing-strategies/constants.ts +++ b/edge-functions/power-parity-pricing-strategies/constants.ts @@ -3,26 +3,26 @@ export const DELAY = process.env.NODE_ENV === 'production' ? 250 : 0 export const REGIONS = { '1': { id: '41891558719737', - discount: 10 + discount: 10, }, '2': { id: '41891558752505', - discount: 20 + discount: 20, }, '3': { id: '41891558785273', - discount: 30 + discount: 30, }, '4': { id: '41891558818041', - discount: 40 + discount: 40, }, '5': { id: '41891558850809', - discount: 50 + discount: 50, }, - 'default': { + default: { id: '41893825478905', - discount: 0 - } -} \ No newline at end of file + discount: 0, + }, +} diff --git a/edge-functions/power-parity-pricing-strategies/types.ts b/edge-functions/power-parity-pricing-strategies/types.ts index 9e06999060..26c39a786a 100644 --- a/edge-functions/power-parity-pricing-strategies/types.ts +++ b/edge-functions/power-parity-pricing-strategies/types.ts @@ -1,11 +1,11 @@ -export type Country = string; +export type Country = string export interface Product { - id: string; - price: number; - name: string; - description: string; - image: string; - link: string; - discount?: number; -} \ No newline at end of file + id: string + price: number + name: string + description: string + image: string + link: string + discount?: number +} diff --git a/edge-functions/power-parity-pricing-strategies/utils.ts b/edge-functions/power-parity-pricing-strategies/utils.ts index 1847fb3c73..61458ffbb2 100644 --- a/edge-functions/power-parity-pricing-strategies/utils.ts +++ b/edge-functions/power-parity-pricing-strategies/utils.ts @@ -1,6 +1,5 @@ export function getDiscountedPrice(price: number, discount: number): string { - return Number(price * ((100 - discount) / 100)).toLocaleString( - 'en-US', - { currency: 'USD' } - ) + return Number(price * ((100 - discount) / 100)).toLocaleString('en-US', { + currency: 'USD', + }) } diff --git a/edge-functions/power-parity-pricing/pages/_app.tsx b/edge-functions/power-parity-pricing/pages/_app.tsx index 766b99ff6b..47f31cd381 100644 --- a/edge-functions/power-parity-pricing/pages/_app.tsx +++ b/edge-functions/power-parity-pricing/pages/_app.tsx @@ -7,7 +7,10 @@ export default function MyApp({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/edge-functions/query-params-filter/pages/_app.tsx b/edge-functions/query-params-filter/pages/_app.tsx index d65eebac79..38e18adbb9 100644 --- a/edge-functions/query-params-filter/pages/_app.tsx +++ b/edge-functions/query-params-filter/pages/_app.tsx @@ -7,7 +7,10 @@ export default function MyApp({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/edge-functions/rewrites-upstash/api.ts b/edge-functions/rewrites-upstash/api.ts index 0b80422b93..60e5a3e8ff 100644 --- a/edge-functions/rewrites-upstash/api.ts +++ b/edge-functions/rewrites-upstash/api.ts @@ -1,36 +1,45 @@ -import { Product } from "./types" +import { Product } from './types' -const PRODUCTS: Product[] = [{ - id: 'mug', - title: 'Vercel Mug', - description: 'Limited edition', - price: 15, - stock: 1 -}, { - id: 'hoodie', - title: 'Vercel Hoodie', - description: 'Limited edition', - price: 35, - stock: 1 -}] +const PRODUCTS: Product[] = [ + { + id: 'mug', + title: 'Vercel Mug', + description: 'Limited edition', + price: 15, + stock: 1, + }, + { + id: 'hoodie', + title: 'Vercel Hoodie', + description: 'Limited edition', + price: 35, + stock: 1, + }, +] const api = { list: async () => { return PRODUCTS }, fetch: async (id: Product['id']) => { - return PRODUCTS.find(product => product.id === id) + return PRODUCTS.find((product) => product.id === id) }, cache: { get: async (product: Product['id']): Promise => { - return await fetch(`${process.env.UPSTASH_REDIS_REST_URL}/get/${product}?_token=${process.env.UPSTASH_REDIS_REST_TOKEN}`) - .then(response => response.json()).then(response => response.result === "true") + return await fetch( + `${process.env.UPSTASH_REDIS_REST_URL}/get/${product}?_token=${process.env.UPSTASH_REDIS_REST_TOKEN}` + ) + .then((response) => response.json()) + .then((response) => response.result === 'true') }, set: async (product: Product['id'], hasStock: boolean) => { - return await fetch(`${process.env.UPSTASH_REDIS_REST_URL}/set/${product}/${hasStock}?_token=${process.env.UPSTASH_REDIS_REST_TOKEN}`) - .then(response => response.json()).then(response => response.result === "true") - } - } + return await fetch( + `${process.env.UPSTASH_REDIS_REST_URL}/set/${product}/${hasStock}?_token=${process.env.UPSTASH_REDIS_REST_TOKEN}` + ) + .then((response) => response.json()) + .then((response) => response.result === 'true') + }, + }, } export default api diff --git a/edge-functions/rewrites-upstash/components/ProductCard.tsx b/edge-functions/rewrites-upstash/components/ProductCard.tsx index f721d27c30..35141ae481 100644 --- a/edge-functions/rewrites-upstash/components/ProductCard.tsx +++ b/edge-functions/rewrites-upstash/components/ProductCard.tsx @@ -1,10 +1,10 @@ -import type { Product } from "../types" +import type { Product } from '../types' interface Props { - product: Product; + product: Product } -export default function ProductCard({product}: Props) { +export default function ProductCard({ product }: Props) { return (
    @@ -19,5 +19,5 @@ export default function ProductCard({product}: Props) {

    - ); -} \ No newline at end of file + ) +} diff --git a/edge-functions/rewrites-upstash/pages/_app.tsx b/edge-functions/rewrites-upstash/pages/_app.tsx index 30638a7bfb..ce1397d2db 100644 --- a/edge-functions/rewrites-upstash/pages/_app.tsx +++ b/edge-functions/rewrites-upstash/pages/_app.tsx @@ -9,10 +9,7 @@ function App({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/edge-functions/rewrites-upstash/pages/api/product/[id]/stock.ts b/edge-functions/rewrites-upstash/pages/api/product/[id]/stock.ts index b3bc740cdc..2fe9b6a1a9 100644 --- a/edge-functions/rewrites-upstash/pages/api/product/[id]/stock.ts +++ b/edge-functions/rewrites-upstash/pages/api/product/[id]/stock.ts @@ -1,16 +1,16 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import { NextApiRequest, NextApiResponse } from 'next' -import api from "../../../../api" +import api from '../../../../api' interface Request extends NextApiRequest { query: { - id: string; + id: string } } export default async function handler(req: Request, res: NextApiResponse) { // If req.method is "POST", add stock, remove it otherwise - const hasStock = req.method === "POST" + const hasStock = req.method === 'POST' // Add or remove stock await api.cache.set(req.query.id, hasStock) diff --git a/edge-functions/rewrites-upstash/pages/product/[id]/index.tsx b/edge-functions/rewrites-upstash/pages/product/[id]/index.tsx index bf5a44d441..f91a3baa31 100644 --- a/edge-functions/rewrites-upstash/pages/product/[id]/index.tsx +++ b/edge-functions/rewrites-upstash/pages/product/[id]/index.tsx @@ -9,27 +9,29 @@ import ProductCard from '../../../components/ProductCard' import { useState } from 'react' interface Props { - product: Product; + product: Product } interface Query extends ParsedUrlQuery { - id: string; + id: string } -export const getStaticProps: GetStaticProps = async ({params}) => { +export const getStaticProps: GetStaticProps = async ({ + params, +}) => { const product = await api.fetch((params as Query).id) if (!product) { return { - notFound: true + notFound: true, } } return { revalidate: 10, props: { - product - } + product, + }, } } @@ -37,22 +39,24 @@ export const getStaticPaths: GetStaticPaths = async () => { const products = await api.list() return { - paths: products.map(product => ({ + paths: products.map((product) => ({ params: { - id: product.id + id: product.id, }, })), - fallback: 'blocking' + fallback: 'blocking', } } -function ProductDetails({product}: Props) { - const [isLoading, toggleLoading] = useState(false); +function ProductDetails({ product }: Props) { + const [isLoading, toggleLoading] = useState(false) function handleBuy() { toggleLoading(true) - fetch(`/api/product/${product.id}/stock`, {method: 'DELETE'}).then(() => window.location.reload()) + fetch(`/api/product/${product.id}/stock`, { method: 'DELETE' }).then(() => + window.location.reload() + ) } return ( @@ -61,7 +65,9 @@ function ProductDetails({product}: Props) { {product.stock ? ( <> - + ) : (
    diff --git a/edge-functions/rewrites-upstash/pages/product/[id]/no-stock.tsx b/edge-functions/rewrites-upstash/pages/product/[id]/no-stock.tsx index 3504422777..2583943e1d 100644 --- a/edge-functions/rewrites-upstash/pages/product/[id]/no-stock.tsx +++ b/edge-functions/rewrites-upstash/pages/product/[id]/no-stock.tsx @@ -8,49 +8,53 @@ import api from '../../../api' import { useState } from 'react' interface Props { - product: Product; + product: Product } interface Query extends ParsedUrlQuery { - id: string; + id: string } export const getStaticPaths: GetStaticPaths = async () => { const products = await api.list() return { - paths: products.map(product => ({ + paths: products.map((product) => ({ params: { - id: product.id + id: product.id, }, })), - fallback: 'blocking' + fallback: 'blocking', } } -export const getStaticProps: GetStaticProps = async ({params}) => { +export const getStaticProps: GetStaticProps = async ({ + params, +}) => { const product = await api.fetch(params?.id as string) if (!product) { return { - notFound: true + notFound: true, } } return { props: { product, - } + }, } } -function NoStock({product}: Props) { - const [isLoading, toggleLoading] = useState(false); +function NoStock({ product }: Props) { + const [isLoading, toggleLoading] = useState(false) function handleAddStock() { toggleLoading(true) - fetch(`/api/product/${product.id}/stock`, {method: 'POST'}).then(() => window.location.reload()) + fetch(`/api/product/${product.id}/stock`, { method: 'POST' }).then(() => + window.location.reload() + ) } return ( @@ -60,7 +64,9 @@ function NoStock({product}: Props) { This product is awesome ({product.title})! But we ran out of stock 😓
    - + Go back to index diff --git a/edge-functions/rewrites-upstash/types.ts b/edge-functions/rewrites-upstash/types.ts index 859b324edf..e90e3825fb 100644 --- a/edge-functions/rewrites-upstash/types.ts +++ b/edge-functions/rewrites-upstash/types.ts @@ -1,7 +1,7 @@ export interface Product { - id: string; - title: string; - description: string; - price: number; - stock: number; -} \ No newline at end of file + id: string + title: string + description: string + price: number + stock: number +} diff --git a/package.json b/package.json index 98149f4cb6..0fc8d4aaa9 100644 --- a/package.json +++ b/package.json @@ -11,4 +11,4 @@ "prettier": "^2.5.1", "plop": "^3.0.5" } -} \ No newline at end of file +} diff --git a/solutions/auth-with-ory/components/Card/Card.module.css b/solutions/auth-with-ory/components/Card/Card.module.css index 286c165ea0..48f5c474b5 100644 --- a/solutions/auth-with-ory/components/Card/Card.module.css +++ b/solutions/auth-with-ory/components/Card/Card.module.css @@ -47,7 +47,7 @@ display: flex; align-items: center; gap: 6px; - background-color: rgba(0,0,0,0.5); + background-color: rgba(0, 0, 0, 0.5); border-radius: 6px; padding: 6px; color: white; @@ -83,7 +83,8 @@ font-size: 14px; } -.contentType, .richType { +.contentType, +.richType { height: 24px; } @@ -111,4 +112,4 @@ border-radius: 9999px; width: 28px; height: 28px; -} \ No newline at end of file +} diff --git a/solutions/auth-with-ory/components/Card/Card.tsx b/solutions/auth-with-ory/components/Card/Card.tsx index 317abfd045..faddfc92d1 100644 --- a/solutions/auth-with-ory/components/Card/Card.tsx +++ b/solutions/auth-with-ory/components/Card/Card.tsx @@ -1,15 +1,15 @@ -import React from "react"; +import React from 'react' -import Image from "next/image" +import Image from 'next/image' -import styles from "./Card.module.css" +import styles from './Card.module.css' interface Props { - title: string; - children: React.ReactElement; + title: string + children: React.ReactElement } -const Card: React.VFC = ({title, children}: Props) => { +const Card: React.VFC = ({ title, children }: Props) => { return (
    @@ -17,36 +17,89 @@ const Card: React.VFC = ({title, children}: Props) => { className: styles.thumbnail })}
    - some image + some image
    - + + + 08:01
    -

    - {title} -

    +

    {title}

    -
    - -

    Development

    -
    +
    + + + +

    Development

    +
    - + + + +

    Trending

    - Avatar + Avatar

    Acme Development

    - ); + ) } -export default Card; +export default Card diff --git a/solutions/auth-with-ory/components/Card/index.ts b/solutions/auth-with-ory/components/Card/index.ts index b41d9aeed0..95cfda28ea 100644 --- a/solutions/auth-with-ory/components/Card/index.ts +++ b/solutions/auth-with-ory/components/Card/index.ts @@ -1 +1 @@ -export {default} from './Card'; +export { default } from './Card' diff --git a/solutions/cms-contentstack-commerce/README.md b/solutions/cms-contentstack-commerce/README.md index cc4492abf0..172241cec7 100644 --- a/solutions/cms-contentstack-commerce/README.md +++ b/solutions/cms-contentstack-commerce/README.md @@ -32,7 +32,6 @@ Copy the `.env.example` file in this directory to `.env.local` and set your Cont cp .env.example .env.local ``` - Next, run Next.js in development mode: ```bash diff --git a/solutions/cms-contentstack-commerce/components/icons/MapPin.tsx b/solutions/cms-contentstack-commerce/components/icons/MapPin.tsx index e3af27537c..686ad9f31d 100644 --- a/solutions/cms-contentstack-commerce/components/icons/MapPin.tsx +++ b/solutions/cms-contentstack-commerce/components/icons/MapPin.tsx @@ -1,12 +1,21 @@ const MapPin = ({ ...props }) => { - return ( - - - - ) - } - - export default MapPin - \ No newline at end of file + return ( + + + + + ) +} + +export default MapPin diff --git a/solutions/cms-contentstack-commerce/components/icons/Menu.tsx b/solutions/cms-contentstack-commerce/components/icons/Menu.tsx index 85337e986e..895e226d85 100644 --- a/solutions/cms-contentstack-commerce/components/icons/Menu.tsx +++ b/solutions/cms-contentstack-commerce/components/icons/Menu.tsx @@ -1,10 +1,21 @@ const Heart = ({ ...props }) => { return ( - - - + + + + + ) } diff --git a/solutions/cms-contentstack-commerce/components/icons/Search.tsx b/solutions/cms-contentstack-commerce/components/icons/Search.tsx index e7f3aaf0eb..b8e5b1dbe0 100644 --- a/solutions/cms-contentstack-commerce/components/icons/Search.tsx +++ b/solutions/cms-contentstack-commerce/components/icons/Search.tsx @@ -1,9 +1,19 @@ const Info = ({ ...props }) => { return ( - - + + + + ) } diff --git a/solutions/cms-contentstack-commerce/lib/contentstack.ts b/solutions/cms-contentstack-commerce/lib/contentstack.ts index b879689e68..9cc66db86c 100644 --- a/solutions/cms-contentstack-commerce/lib/contentstack.ts +++ b/solutions/cms-contentstack-commerce/lib/contentstack.ts @@ -20,18 +20,15 @@ export default { ): Promise { // https://www.contentstack.com/docs/developers/apis/content-delivery-api/#get-a-single-entry try { - const cmsEnv = process.env.CONTENTSTACK_ENV ?? process.env.NODE_ENV; - const entryApiUrl = `${API_URL}/content_types/${contentType}/entries/${entryId}?locale=${locale.toLocaleLowerCase()}&environment=${cmsEnv}`; - const res: any = await fetch( - entryApiUrl, - { - method: 'GET', - headers: { - api_key: process.env.CONTENTSTACK_API_KEY as string, - access_token: process.env.CONTENTSTACK_ACCESS_TOKEN as string, - }, - } - ) + const cmsEnv = process.env.CONTENTSTACK_ENV ?? process.env.NODE_ENV + const entryApiUrl = `${API_URL}/content_types/${contentType}/entries/${entryId}?locale=${locale.toLocaleLowerCase()}&environment=${cmsEnv}` + const res: any = await fetch(entryApiUrl, { + method: 'GET', + headers: { + api_key: process.env.CONTENTSTACK_API_KEY as string, + access_token: process.env.CONTENTSTACK_ACCESS_TOKEN as string, + }, + }) const { entry } = await res.json() return entry diff --git a/solutions/cms-contentstack-commerce/pages/index.tsx b/solutions/cms-contentstack-commerce/pages/index.tsx index 31879bfe5f..1bf284ed03 100644 --- a/solutions/cms-contentstack-commerce/pages/index.tsx +++ b/solutions/cms-contentstack-commerce/pages/index.tsx @@ -13,7 +13,7 @@ export async function getStaticProps({ const entry = await cs.getEntry( // hardcoded example 'home_page', - 'blt5c760b6ce70ae18b', + 'blt5c760b6ce70ae18b', locale ? (locale.toLocaleLowerCase() as string) : 'en-US' ) diff --git a/solutions/combining-data-fetching-strategies/pages/api/product/[id]/stock.ts b/solutions/combining-data-fetching-strategies/pages/api/product/[id]/stock.ts index e1918fbf6f..c68a4a49a4 100644 --- a/solutions/combining-data-fetching-strategies/pages/api/product/[id]/stock.ts +++ b/solutions/combining-data-fetching-strategies/pages/api/product/[id]/stock.ts @@ -1,5 +1,5 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import { NextApiRequest, NextApiResponse } from 'next' export default function handler(_req: NextApiRequest, res: NextApiResponse) { - return res.send(Math.floor(Math.random() * 3)); -} \ No newline at end of file + return res.send(Math.floor(Math.random() * 3)) +} diff --git a/solutions/domains-api/components/loading-dots.js b/solutions/domains-api/components/loading-dots.js index e68062856b..2fee46d579 100644 --- a/solutions/domains-api/components/loading-dots.js +++ b/solutions/domains-api/components/loading-dots.js @@ -1,15 +1,13 @@ -import styles from './loading-dots.module.css'; +import styles from './loading-dots.module.css' const LoadingDots = () => { return ( - + - ); -}; + ) +} -export default LoadingDots; \ No newline at end of file +export default LoadingDots diff --git a/solutions/domains-api/pages/api/add-domain.js b/solutions/domains-api/pages/api/add-domain.js index 7e5aea73b2..0b158c795f 100644 --- a/solutions/domains-api/pages/api/add-domain.js +++ b/solutions/domains-api/pages/api/add-domain.js @@ -1,23 +1,25 @@ export default async function addDomain(req, res) { + const { domain } = req.query - const { domain } = req.query; - - const response = await fetch(`https://api.vercel.com/v8/projects/${process.env.VERCEL_PROJECT_ID}/domains?teamId=${process.env.VERCEL_TEAM_ID}`, { - body: `{\n "name": "${domain}"\n}`, - headers: { - Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, - "Content-Type": "application/json" - }, - method: "POST" - }) - - const data = await response.json(); - - if (data.error?.code == 'forbidden') { - res.status(403).end(); - } else if (data.error?.code == 'domain_taken') { - res.status(409).end(); - } else { - res.status(200).end(); + const response = await fetch( + `https://api.vercel.com/v8/projects/${process.env.VERCEL_PROJECT_ID}/domains?teamId=${process.env.VERCEL_TEAM_ID}`, + { + body: `{\n "name": "${domain}"\n}`, + headers: { + Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, + 'Content-Type': 'application/json', + }, + method: 'POST', } + ) + + const data = await response.json() + + if (data.error?.code == 'forbidden') { + res.status(403).end() + } else if (data.error?.code == 'domain_taken') { + res.status(409).end() + } else { + res.status(200).end() + } } diff --git a/solutions/domains-api/pages/api/check-domain.js b/solutions/domains-api/pages/api/check-domain.js index 5902a40c7d..8bd04a5556 100644 --- a/solutions/domains-api/pages/api/check-domain.js +++ b/solutions/domains-api/pages/api/check-domain.js @@ -1,18 +1,20 @@ export default async function checkDomain(req, res) { + const { domain } = req.query - const { domain } = req.query; - - const response = await fetch(`https://api.vercel.com/v6/domains/${domain}/config?teamId=${process.env.VERCEL_TEAM_ID}`, { - method: 'GET', - headers: { - 'Authorization': `Bearer ${process.env.AUTH_BEARER_TOKEN}`, + const response = await fetch( + `https://api.vercel.com/v6/domains/${domain}/config?teamId=${process.env.VERCEL_TEAM_ID}`, + { + method: 'GET', + headers: { + Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, 'Content-Type': 'application/json', - }, - }); - - const data = await response.json(); + }, + } + ) - const valid = data?.configuredBy ? true: false - - res.status(200).json(valid); + const data = await response.json() + + const valid = data?.configuredBy ? true : false + + res.status(200).json(valid) } diff --git a/solutions/domains-api/pages/api/remove-domain.js b/solutions/domains-api/pages/api/remove-domain.js index 013af97cc9..556faa310d 100644 --- a/solutions/domains-api/pages/api/remove-domain.js +++ b/solutions/domains-api/pages/api/remove-domain.js @@ -1,15 +1,17 @@ export default async function removeDomain(req, res) { + const { domain } = req.query - const { domain } = req.query; - - const response = await fetch(`https://api.vercel.com/v8/projects/${process.env.VERCEL_PROJECT_ID}/domains/${domain}?teamId=${process.env.VERCEL_TEAM_ID}`, { - headers: { - Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, - }, - method: "DELETE" - }) - - await response.json(); - - res.status(200).end(); + const response = await fetch( + `https://api.vercel.com/v8/projects/${process.env.VERCEL_PROJECT_ID}/domains/${domain}?teamId=${process.env.VERCEL_TEAM_ID}`, + { + headers: { + Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, + }, + method: 'DELETE', + } + ) + + await response.json() + + res.status(200).end() } diff --git a/solutions/domains-api/pages/api/request-delegation.js b/solutions/domains-api/pages/api/request-delegation.js index 893a0b72a8..29b1feccce 100644 --- a/solutions/domains-api/pages/api/request-delegation.js +++ b/solutions/domains-api/pages/api/request-delegation.js @@ -1,18 +1,20 @@ export default async function requestDelegation(req, res) { + const { domain } = req.query - const { domain } = req.query; - - const response = await fetch(`https://api.vercel.com/v6/domains/${domain}/request-delegation?teamId=${process.env.VERCEL_TEAM_ID}`, { - headers: { - Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, - "Content-Type": "application/json" - }, - method: "POST" - }) - - if (response.ok) { - res.status(200).end(); - } else { - res.status(403).end(); + const response = await fetch( + `https://api.vercel.com/v6/domains/${domain}/request-delegation?teamId=${process.env.VERCEL_TEAM_ID}`, + { + headers: { + Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, + 'Content-Type': 'application/json', + }, + method: 'POST', } + ) + + if (response.ok) { + res.status(200).end() + } else { + res.status(403).end() + } } diff --git a/solutions/domains-api/pages/index.js b/solutions/domains-api/pages/index.js index 4e341ec024..b193c35835 100644 --- a/solutions/domains-api/pages/index.js +++ b/solutions/domains-api/pages/index.js @@ -1,38 +1,38 @@ -import Head from "next/head"; -import { useEffect, useState } from "react"; -import Cookies from "js-cookie"; -import LoadingDots from "../components/loading-dots"; -import toast, { Toaster } from "react-hot-toast"; -import useSWR, { mutate } from "swr"; -const fetcher = (...args) => fetch(...args).then((res) => res.json()); -import Image from "next/image"; +import Head from 'next/head' +import { useEffect, useState } from 'react' +import Cookies from 'js-cookie' +import LoadingDots from '../components/loading-dots' +import toast, { Toaster } from 'react-hot-toast' +import useSWR, { mutate } from 'swr' +const fetcher = (...args) => fetch(...args).then((res) => res.json()) +import Image from 'next/image' export default function Home() { - const [domain, setDomain] = useState(""); + const [domain, setDomain] = useState('') const [domainList, setDomainList] = useState( - Cookies.get("domainList") - ? JSON.parse(Cookies.get("domainList")) - : ["platformizer.co", "vercel.pub"] - ); // initialize the state with two default domains - const [disabled, setDisabled] = useState(true); - const [adding, setAdding] = useState(false); - const [error, setError] = useState(null); + Cookies.get('domainList') + ? JSON.parse(Cookies.get('domainList')) + : ['platformizer.co', 'vercel.pub'] + ) // initialize the state with two default domains + const [disabled, setDisabled] = useState(true) + const [adding, setAdding] = useState(false) + const [error, setError] = useState(null) useEffect(() => { if (domain.length == 0) { - setDisabled(true); + setDisabled(true) } else { - setDisabled(false); + setDisabled(false) } - }, [domain]); + }, [domain]) useEffect(() => { - if (adding) setDisabled(true); - }, [adding]); + if (adding) setDisabled(true) + }, [adding]) useEffect(() => { - Cookies.set("domainList", JSON.stringify(domainList)); - }, [domainList]); + Cookies.set('domainList', JSON.stringify(domainList)) + }, [domainList]) return (
    @@ -59,19 +59,19 @@ export default function Home() {
    { - e.preventDefault(); - setAdding(true); + e.preventDefault() + setAdding(true) await fetch(`/api/add-domain?domain=${domain}`).then((res) => { - setAdding(false); + setAdding(false) if (res.ok) { - setError(null); - setDomainList([...domainList, domain]); - e.target.domain.value = ""; + setError(null) + setDomainList([...domainList, domain]) + e.target.domain.value = '' } else { - const errorDomain = domain; - setError({ code: res.status, domain: errorDomain }); + const errorDomain = domain + setError({ code: res.status, domain: errorDomain }) } - }); + }) }} className="flex justify-between space-x-4 w-full max-w-2xl h-10 mt-10" > @@ -79,7 +79,7 @@ export default function Home() { type="text" name="domain" onInput={(e) => { - setDomain(e.target.value); + setDomain(e.target.value) }} autoComplete="off" placeholder="mydomain.com" @@ -92,11 +92,11 @@ export default function Home() { disabled={disabled} className={`${ disabled - ? "cursor-not-allowed bg-gray-100 text-gray-500 border-gray-300" - : "bg-black text-white border-black hover:text-black hover:bg-white" + ? 'cursor-not-allowed bg-gray-100 text-gray-500 border-gray-300' + : 'bg-black text-white border-black hover:text-black hover:bg-white' } py-2 w-28 text-sm border-solid border rounded-md focus:outline-none transition-all ease-in-out duration-150`} > - {adding ? : "Add"} + {adding ? : 'Add'} @@ -112,7 +112,7 @@ export default function Home() { strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision" - style={{ color: "#f44336" }} + style={{ color: '#f44336' }} > @@ -124,20 +124,20 @@ export default function Home() {
    @@ -173,12 +173,12 @@ export default function Home() { target="_blank" rel="noopener noreferrer" > - Powered by{" "} + Powered by{' '} Vercel Logo - ); + ) } const DomainCard = ({ domain, domainList, setDomainList }) => { @@ -186,9 +186,9 @@ const DomainCard = ({ domain, domainList, setDomainList }) => { `/api/check-domain?domain=${domain}`, fetcher, { revalidateOnMount: true, refreshInterval: 5000 } - ); - const [recordType, setRecordType] = useState("CNAME"); - const [removing, setRemoving] = useState(false); + ) + const [recordType, setRecordType] = useState('CNAME') + const [removing, setRemoving] = useState(false) return (
    @@ -220,35 +220,35 @@ const DomainCard = ({ domain, domainList, setDomainList }) => {
    @@ -263,7 +263,7 @@ const DomainCard = ({ domain, domainList, setDomainList }) => { strokeLinejoin="round" shapeRendering="geometricPrecision" > - + {valid ? ( <> {

    - {valid ? "Valid" : "Invalid"} Configuration + {valid ? 'Valid' : 'Invalid'} Configuration

    @@ -295,21 +295,21 @@ const DomainCard = ({ domain, domainList, setDomainList }) => {
    - ); -}; + ) +} export const getStaticProps: GetStaticProps = async () => { - const products = await api.list(); + const products = await api.list() return { props: { products, date: new Date().toTimeString(), }, - }; -}; + } +} function Home({ products, date }: Props) { async function handleRevalidate() { - await fetch("/api/revalidate"); + await fetch('/api/revalidate') - window.location.reload(); + window.location.reload() } return ( @@ -107,9 +107,9 @@ export async function getStaticProps() { Would not be great if we only regenerate this page when our data - changes? Since Next.js 12.1 we can do that using the{" "} + changes? Since Next.js 12.1 we can do that using the{' '} res.unstable_revalidate (res.revalidate if you come from - a future where this feature is already stable) function in our{" "} + a future where this feature is already stable) function in our{' '} API Routes @@ -179,9 +179,9 @@ export async function getStaticProps() { - ); + ) } -Home.Layout = Layout; +Home.Layout = Layout -export default Home; +export default Home diff --git a/solutions/on-demand-isr/pages/tweets.tsx b/solutions/on-demand-isr/pages/tweets.tsx index 0f294e364d..17e47451d3 100644 --- a/solutions/on-demand-isr/pages/tweets.tsx +++ b/solutions/on-demand-isr/pages/tweets.tsx @@ -1,15 +1,15 @@ -import type { Tweet as ITweet } from "../types"; +import type { Tweet as ITweet } from '../types' -import Head from "next/head"; -import { Layout, Text, Page, Code, Link } from "@vercel/examples-ui"; +import Head from 'next/head' +import { Layout, Text, Page, Code, Link } from '@vercel/examples-ui' -import { GetStaticProps } from "next"; -import api from "../api"; -import Snippet from "../components/Snippet"; +import { GetStaticProps } from 'next' +import api from '../api' +import Snippet from '../components/Snippet' interface Props { - tweets: ITweet[]; - date: string; + tweets: ITweet[] + date: string } const Tweet: React.VFC<{ tweet: ITweet }> = ({ tweet }) => { @@ -19,19 +19,19 @@ const Tweet: React.VFC<{ tweet: ITweet }> = ({ tweet }) => { {decodeURIComponent(tweet.text)} - ); -}; + ) +} export const getStaticProps: GetStaticProps = async () => { - const tweets = await api.tweets(); + const tweets = await api.tweets() return { props: { tweets, date: new Date().toTimeString(), }, - }; -}; + } +} function Tweets({ tweets, date }: Props) { return ( @@ -72,7 +72,7 @@ function Tweets({ tweets, date }: Props) {
    - +
    {tweets.map((tweet) => ( @@ -87,9 +87,9 @@ function Tweets({ tweets, date }: Props) { Back to home
    - ); + ) } -Tweets.Layout = Layout; +Tweets.Layout = Layout -export default Tweets; +export default Tweets diff --git a/solutions/on-demand-isr/types.ts b/solutions/on-demand-isr/types.ts index a095359a20..a06cd7f98a 100644 --- a/solutions/on-demand-isr/types.ts +++ b/solutions/on-demand-isr/types.ts @@ -1,14 +1,14 @@ export interface Product { - id: string; - title: string; - image: string; - price: string; - description: string; - category: string; - hasStock: boolean; + id: string + title: string + image: string + price: string + description: string + category: string + hasStock: boolean } export interface Tweet { - id: string; - text: string; -} \ No newline at end of file + id: string + text: string +} diff --git a/solutions/platforms-slate-supabase/components/BlogCard.js b/solutions/platforms-slate-supabase/components/BlogCard.js index 216f0c4211..c0e0e55567 100644 --- a/solutions/platforms-slate-supabase/components/BlogCard.js +++ b/solutions/platforms-slate-supabase/components/BlogCard.js @@ -1,6 +1,6 @@ -import Link from "next/link"; -import BlurImage from "./BlurImage"; -import Date from "./Date"; +import Link from 'next/link' +import BlurImage from './BlurImage' +import Date from './Date' export default function BlogCard({ data }) { return ( @@ -29,5 +29,5 @@ export default function BlogCard({ data }) { - ); + ) } diff --git a/solutions/platforms-slate-supabase/components/BlurImage.js b/solutions/platforms-slate-supabase/components/BlurImage.js index a6e9cd297c..f494b412bc 100644 --- a/solutions/platforms-slate-supabase/components/BlurImage.js +++ b/solutions/platforms-slate-supabase/components/BlurImage.js @@ -1,9 +1,9 @@ -import Image from "next/image"; -import { useState } from "react"; -import cn from "clsx"; +import Image from 'next/image' +import { useState } from 'react' +import cn from 'clsx' export default function BlurImage(props) { - const [isLoading, setLoading] = useState(true); + const [isLoading, setLoading] = useState(true) return ( {props.alt} setLoading(false)} /> - ); + ) } diff --git a/solutions/platforms-slate-supabase/components/Cloudinary.js b/solutions/platforms-slate-supabase/components/Cloudinary.js index 84019d54b4..69c5091059 100644 --- a/solutions/platforms-slate-supabase/components/Cloudinary.js +++ b/solutions/platforms-slate-supabase/components/Cloudinary.js @@ -1,33 +1,33 @@ -import { Component } from "react"; -import Head from "next/head"; +import { Component } from 'react' +import Head from 'next/head' export default class CloudinaryUploadWidget extends Component { constructor(props) { - super(props); - this.uploader = null; + super(props) + this.uploader = null } showWidget = () => { - const { callback } = this.props; + const { callback } = this.props let widget = window.cloudinary.createUploadWidget( { - cloudName: "vercel-platforms", - uploadPreset: "w0vnflc6", + cloudName: 'vercel-platforms', + uploadPreset: 'w0vnflc6', cropping: true, }, (error, result) => { - if (!error && result && result.event === "success") { - callback(result.info); + if (!error && result && result.event === 'success') { + callback(result.info) } } - ); - widget.open(); - }; + ) + widget.open() + } open = (e) => { - e.preventDefault(); - this.showWidget(); - }; + e.preventDefault() + this.showWidget() + } render() { return ( @@ -43,6 +43,6 @@ export default class CloudinaryUploadWidget extends Component { {this.props.children({ open: this.open })} - ); + ) } } diff --git a/solutions/platforms-slate-supabase/components/Date.js b/solutions/platforms-slate-supabase/components/Date.js index 4c510746b4..4c7f5ad7d0 100644 --- a/solutions/platforms-slate-supabase/components/Date.js +++ b/solutions/platforms-slate-supabase/components/Date.js @@ -1,6 +1,6 @@ -import { parseISO, format } from "date-fns"; +import { parseISO, format } from 'date-fns' export default function Date({ dateString }) { - const date = parseISO(dateString); - return ; + const date = parseISO(dateString) + return } diff --git a/solutions/platforms-slate-supabase/components/Logo.js b/solutions/platforms-slate-supabase/components/Logo.js index 7e6e6d61e0..373ed5ad4d 100644 --- a/solutions/platforms-slate-supabase/components/Logo.js +++ b/solutions/platforms-slate-supabase/components/Logo.js @@ -9,12 +9,12 @@ const Logo = (props) => { > DAO Jones Logo - + - ); -}; + ) +} -export default Logo; +export default Logo diff --git a/solutions/platforms-slate-supabase/components/LogoSmall.js b/solutions/platforms-slate-supabase/components/LogoSmall.js index 8f04db964c..b9c4df6012 100644 --- a/solutions/platforms-slate-supabase/components/LogoSmall.js +++ b/solutions/platforms-slate-supabase/components/LogoSmall.js @@ -13,7 +13,7 @@ const LogoSmall = (props) => { - ); -}; + ) +} -export default LogoSmall; +export default LogoSmall diff --git a/solutions/platforms-slate-supabase/components/Modal.js b/solutions/platforms-slate-supabase/components/Modal.js index a3d2c6d91d..c6db2df537 100644 --- a/solutions/platforms-slate-supabase/components/Modal.js +++ b/solutions/platforms-slate-supabase/components/Modal.js @@ -1,5 +1,5 @@ -import { Dialog, Transition } from "@headlessui/react"; -import { Fragment } from "react"; +import { Dialog, Transition } from '@headlessui/react' +import { Fragment } from 'react' export default function Modal({ children, showModal, setShowModal }) { return ( @@ -44,5 +44,5 @@ export default function Modal({ children, showModal, setShowModal }) { - ); + ) } diff --git a/solutions/platforms-slate-supabase/components/app/DomainCard.js b/solutions/platforms-slate-supabase/components/app/DomainCard.js index 45617335eb..e847ce7c1f 100644 --- a/solutions/platforms-slate-supabase/components/app/DomainCard.js +++ b/solutions/platforms-slate-supabase/components/app/DomainCard.js @@ -1,16 +1,16 @@ -import useSWR, { mutate } from "swr"; -const fetcher = (...args) => fetch(...args).then((res) => res.json()); -import { useState } from "react"; -import LoadingDots from "@/components/app/loading-dots"; +import useSWR, { mutate } from 'swr' +const fetcher = (...args) => fetch(...args).then((res) => res.json()) +import { useState } from 'react' +import LoadingDots from '@/components/app/loading-dots' const DomainCard = ({ data, setData }) => { const { data: valid, isValidating } = useSWR( `/api/check-domain?domain=${data.customDomain}`, fetcher, { revalidateOnMount: true, refreshInterval: 5000 } - ); - const [recordType, setRecordType] = useState("CNAME"); - const [removing, setRemoving] = useState(false); + ) + const [recordType, setRecordType] = useState('CNAME') + const [removing, setRemoving] = useState(false) return (
    @@ -42,37 +42,37 @@ const DomainCard = ({ data, setData }) => {
    @@ -87,7 +87,7 @@ const DomainCard = ({ data, setData }) => { strokeLinejoin="round" shapeRendering="geometricPrecision" > - + {valid ? ( <> {

    - {valid ? "Valid" : "Invalid"} Configuration + {valid ? 'Valid' : 'Invalid'} Configuration

    @@ -119,21 +119,21 @@ const DomainCard = ({ data, setData }) => {
    @@ -166,7 +166,7 @@ const DomainCard = ({ data, setData }) => { )}
    - ); -}; + ) +} -export default DomainCard; +export default DomainCard diff --git a/solutions/platforms-slate-supabase/components/app/Layout.js b/solutions/platforms-slate-supabase/components/app/Layout.js index 0ac8dbf35f..6a1ca769e3 100644 --- a/solutions/platforms-slate-supabase/components/app/Layout.js +++ b/solutions/platforms-slate-supabase/components/app/Layout.js @@ -1,27 +1,27 @@ -import Head from "next/head"; -import Link from "next/link"; -import Image from "next/image"; -import { useRouter } from "next/router"; -import React from "react"; -import { signOut } from "next-auth/react"; -import Loader from "./Loader"; -import useRequireAuth from "../../lib/useRequireAuth"; +import Head from 'next/head' +import Link from 'next/link' +import Image from 'next/image' +import { useRouter } from 'next/router' +import React from 'react' +import { signOut } from 'next-auth/react' +import Loader from './Loader' +import useRequireAuth from '../../lib/useRequireAuth' export default function Layout({ siteId, children }) { - const title = "Platforms on Vercel"; + const title = 'Platforms on Vercel' const description = - "Create a fullstack application with multi-tenancy and custom domains support using Next.js, Supabase, and PostgreSQL"; - const logo = "/favicon.ico"; - const router = useRouter(); - const sitePage = router.pathname.startsWith("/app/site/[id]"); - const postPage = router.pathname.startsWith("/app/post/[id]"); - const rootPage = !sitePage && !postPage; + 'Create a fullstack application with multi-tenancy and custom domains support using Next.js, Supabase, and PostgreSQL' + const logo = '/favicon.ico' + const router = useRouter() + const sitePage = router.pathname.startsWith('/app/site/[id]') + const postPage = router.pathname.startsWith('/app/post/[id]') + const rootPage = !sitePage && !postPage const tab = rootPage - ? router.asPath.split("/")[1] - : router.asPath.split("/")[3]; + ? router.asPath.split('/')[1] + : router.asPath.split('/')[3] - const session = useRequireAuth(); - if (!session) return ; + const session = useRequireAuth() + if (!session) return return ( <> @@ -101,7 +101,7 @@ export default function Layout({ siteId, children }) { My Sites @@ -121,7 +121,7 @@ export default function Layout({ siteId, children }) { Posts @@ -130,7 +130,7 @@ export default function Layout({ siteId, children }) { Drafts @@ -152,7 +152,7 @@ export default function Layout({ siteId, children }) { ) : (
    - {" "} + {' '} ←

    All Posts

    )} @@ -161,7 +161,7 @@ export default function Layout({ siteId, children }) {
    Editor @@ -170,7 +170,7 @@ export default function Layout({ siteId, children }) { Settings @@ -184,5 +184,5 @@ export default function Layout({ siteId, children }) {
    {children}
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/components/app/Loader.js b/solutions/platforms-slate-supabase/components/app/Loader.js index 8e87abd143..da831666ce 100644 --- a/solutions/platforms-slate-supabase/components/app/Loader.js +++ b/solutions/platforms-slate-supabase/components/app/Loader.js @@ -1,5 +1,5 @@ export default function Loader() { - let circleCommonClasses = "h-4 w-4 bg-black rounded-full"; + let circleCommonClasses = 'h-4 w-4 bg-black rounded-full' return (
    @@ -8,5 +8,5 @@ export default function Loader() {
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/components/app/loading-dots.js b/solutions/platforms-slate-supabase/components/app/loading-dots.js index 99330e4f0a..32d121f89c 100644 --- a/solutions/platforms-slate-supabase/components/app/loading-dots.js +++ b/solutions/platforms-slate-supabase/components/app/loading-dots.js @@ -1,13 +1,13 @@ -import styles from "./loading-dots.module.css"; +import styles from './loading-dots.module.css' -const LoadingDots = ({ color = "#000" }) => { +const LoadingDots = ({ color = '#000' }) => { return ( - ); -}; + ) +} -export default LoadingDots; +export default LoadingDots diff --git a/solutions/platforms-slate-supabase/components/editor/Element.js b/solutions/platforms-slate-supabase/components/editor/Element.js index 55863039f0..0ea07f8891 100644 --- a/solutions/platforms-slate-supabase/components/editor/Element.js +++ b/solutions/platforms-slate-supabase/components/editor/Element.js @@ -1,44 +1,44 @@ -export default function Element({ attributes, children, element }){ - switch (element.type) { - case "block-quote": - return
    {children}
    ; - case "italic": - return ( - - {children} - - ) - case "underline": - return ( -

    - {children} -

    - ); - - case "heading-one": - return ( -

    - {children} -

    - ); - case "heading-two": - return ( -

    - {children} -

    - ); - case "code": - return ( - - {children} - - ); - - case "list-item": - return
  • {children}
  • ; - case "numbered-list": - return
      {children}
    ; - default: - return

    {children}

    ; - } - }; \ No newline at end of file +export default function Element({ attributes, children, element }) { + switch (element.type) { + case 'block-quote': + return
    {children}
    + case 'italic': + return ( + + {children} + + ) + case 'underline': + return ( +

    + {children} +

    + ) + + case 'heading-one': + return ( +

    + {children} +

    + ) + case 'heading-two': + return ( +

    + {children} +

    + ) + case 'code': + return ( + + {children} + + ) + + case 'list-item': + return
  • {children}
  • + case 'numbered-list': + return
      {children}
    + default: + return

    {children}

    + } +} diff --git a/solutions/platforms-slate-supabase/components/editor/Leaf.js b/solutions/platforms-slate-supabase/components/editor/Leaf.js index f7e5e7ef3b..d7375cb72a 100644 --- a/solutions/platforms-slate-supabase/components/editor/Leaf.js +++ b/solutions/platforms-slate-supabase/components/editor/Leaf.js @@ -2,28 +2,28 @@ import Highlight from 'react-highlight' export default function Leaf({ attributes, children, leaf }) { if (leaf.bold) { - children = {children}; + children = {children} } if (leaf.code) { - children = {children}; + children = {children} } if (leaf.italic) { - children = {children}; + children = {children} } if (leaf.underline) { - children = {children}; + children = {children} } - if (leaf["heading-one"]) { - children =

    {children}

    ; + if (leaf['heading-one']) { + children =

    {children}

    } - if (leaf["heading-two"]) { - children =

    {children}

    ; + if (leaf['heading-two']) { + children =

    {children}

    } - return {children}; + return {children} } diff --git a/solutions/platforms-slate-supabase/components/editor/TextEditor.js b/solutions/platforms-slate-supabase/components/editor/TextEditor.js index 846c83bf19..b45f05c217 100644 --- a/solutions/platforms-slate-supabase/components/editor/TextEditor.js +++ b/solutions/platforms-slate-supabase/components/editor/TextEditor.js @@ -1,66 +1,65 @@ -import React, { useCallback, useMemo, useState } from "react"; -import isHotkey from "is-hotkey"; -import { Editable, withReact, useSlate, Slate } from "slate-react"; -import { Editor, createEditor } from "slate"; -import { withHistory } from "slate-history"; +import React, { useCallback, useMemo, useState } from 'react' +import isHotkey from 'is-hotkey' +import { Editable, withReact, useSlate, Slate } from 'slate-react' +import { Editor, createEditor } from 'slate' +import { withHistory } from 'slate-history' import Element from './Element' import Leaf from './Leaf' const HOTKEYS = { - "cmd+b": "bold", - "cmd+i": "italic", - "cmd+u": "underline", - "cmd+c": "code", -}; + 'cmd+b': 'bold', + 'cmd+i': 'italic', + 'cmd+u': 'underline', + 'cmd+c': 'code', +} const isMarkActive = (editor, format) => { - const marks = Editor.marks(editor); - return marks ? marks[format] === true : false; -}; - + const marks = Editor.marks(editor) + return marks ? marks[format] === true : false +} const Button = React.forwardRef(({ active, ...children }) => ( -)); +)) const TextEditor = (props) => { - const [value, setValue] = useState(props.initialValue); - const renderElement = useCallback((props) => , []); - const renderLeaf = useCallback((props) => , []); - const editor = useMemo(() => withHistory(withReact(createEditor())), []); - const [currentMark, setCurrentMark] = useState(null); + const [value, setValue] = useState(props.initialValue) + const renderElement = useCallback((props) => , []) + const renderLeaf = useCallback((props) => , []) + const editor = useMemo(() => withHistory(withReact(createEditor())), []) + const [currentMark, setCurrentMark] = useState(null) const toggleMark = (editor, format) => { - const isActive = isMarkActive(editor, format); + const isActive = isMarkActive(editor, format) if (isActive) { - Editor.removeMark(editor, format); + Editor.removeMark(editor, format) } else { - Editor.addMark(editor, format, true); + Editor.addMark(editor, format, true) } - }; + } const ToolbarButton = ({ format, icon }) => { - const editor = useSlate(); + const editor = useSlate() if (isMarkActive(editor, format)) { - setCurrentMark(format); + setCurrentMark(format) } return ( - ); - }; + ) + } return ( setValue(value)}> @@ -88,22 +87,22 @@ const TextEditor = (props) => { spellCheck autoFocus onKeyDown={(event) => { - if (event.key === "Enter") { - toggleMark(editor, currentMark); - setCurrentMark(null); + if (event.key === 'Enter') { + toggleMark(editor, currentMark) + setCurrentMark(null) } for (const hotkey in HOTKEYS) { if (isHotkey(hotkey, event)) { - event.preventDefault(); - const mark = HOTKEYS[hotkey]; - toggleMark(editor, mark); - setCurrentMark(mark); + event.preventDefault() + const mark = HOTKEYS[hotkey] + toggleMark(editor, mark) + setCurrentMark(mark) } } }} /> - ); -}; + ) +} -export default TextEditor; +export default TextEditor diff --git a/solutions/platforms-slate-supabase/components/icons/link.js b/solutions/platforms-slate-supabase/components/icons/link.js index 85c054b334..de280b973b 100644 --- a/solutions/platforms-slate-supabase/components/icons/link.js +++ b/solutions/platforms-slate-supabase/components/icons/link.js @@ -1,4 +1,4 @@ -import React from "react"; +import React from 'react' function LinkIcon({ width, height, color }) { return ( @@ -20,7 +20,7 @@ function LinkIcon({ width, height, color }) { className="st0" >
    - ); + ) } -export default LinkIcon; +export default LinkIcon diff --git a/solutions/platforms-slate-supabase/components/icons/not-found.js b/solutions/platforms-slate-supabase/components/icons/not-found.js index fd7726487e..82331a11fb 100644 --- a/solutions/platforms-slate-supabase/components/icons/not-found.js +++ b/solutions/platforms-slate-supabase/components/icons/not-found.js @@ -15,7 +15,7 @@ const NotFoundIcon = ({ color, width, height, className }) => { - ); -}; + ) +} -export default NotFoundIcon; +export default NotFoundIcon diff --git a/solutions/platforms-slate-supabase/components/icons/plus.js b/solutions/platforms-slate-supabase/components/icons/plus.js index 1df3a599bc..a74f185144 100644 --- a/solutions/platforms-slate-supabase/components/icons/plus.js +++ b/solutions/platforms-slate-supabase/components/icons/plus.js @@ -14,7 +14,7 @@ const PlusIcon = ({ color, width, height, className }) => { - ); -}; + ) +} -export default PlusIcon; +export default PlusIcon diff --git a/solutions/platforms-slate-supabase/components/icons/search.js b/solutions/platforms-slate-supabase/components/icons/search.js index 482589f022..2a3026368b 100644 --- a/solutions/platforms-slate-supabase/components/icons/search.js +++ b/solutions/platforms-slate-supabase/components/icons/search.js @@ -16,7 +16,7 @@ const SearchIcon = ({ color, width, height, className }) => { className="st0" >
    - ); -}; + ) +} -export default SearchIcon; +export default SearchIcon diff --git a/solutions/platforms-slate-supabase/components/icons/twitter.js b/solutions/platforms-slate-supabase/components/icons/twitter.js index 4d3a0f8c03..c91ce54cb2 100644 --- a/solutions/platforms-slate-supabase/components/icons/twitter.js +++ b/solutions/platforms-slate-supabase/components/icons/twitter.js @@ -13,7 +13,7 @@ const TwitterIcon = ({ color, width, height, className }) => { Twitter Icon - ); -}; + ) +} -export default TwitterIcon; +export default TwitterIcon diff --git a/solutions/platforms-slate-supabase/components/icons/x.js b/solutions/platforms-slate-supabase/components/icons/x.js index 9907bd12f5..b204a4b201 100644 --- a/solutions/platforms-slate-supabase/components/icons/x.js +++ b/solutions/platforms-slate-supabase/components/icons/x.js @@ -18,7 +18,7 @@ const XIcon = ({ color, width, height, className }) => { c18.7,19.36,49.52,19.89,68.89,1.19c19.36-18.65,19.89-49.52,1.19-68.89l-1.19-1.19L324.91,255.96V256z" /> - ); -}; + ) +} -export default XIcon; +export default XIcon diff --git a/solutions/platforms-slate-supabase/components/sites/Layout.js b/solutions/platforms-slate-supabase/components/sites/Layout.js index 0e89481872..757e925cf4 100644 --- a/solutions/platforms-slate-supabase/components/sites/Layout.js +++ b/solutions/platforms-slate-supabase/components/sites/Layout.js @@ -1,30 +1,30 @@ -import Head from "next/head"; -import Link from "next/link"; -import Image from "next/image"; -import { useState, useEffect, useCallback } from "react"; -import Cookies from "js-cookie"; +import Head from 'next/head' +import Link from 'next/link' +import Image from 'next/image' +import { useState, useEffect, useCallback } from 'react' +import Cookies from 'js-cookie' export default function Layout({ meta, children, subdomain }) { - const [scrolled, setScrolled] = useState(false); + const [scrolled, setScrolled] = useState(false) const onScroll = useCallback(() => { - setScrolled(window.pageYOffset > 20); - }, []); + setScrolled(window.pageYOffset > 20) + }, []) useEffect(() => { - window.addEventListener("scroll", onScroll); - return () => window.removeEventListener("scroll", onScroll); - }, [onScroll]); + window.addEventListener('scroll', onScroll) + return () => window.removeEventListener('scroll', onScroll) + }, [onScroll]) - const [closeModal, setCloseModal] = useState(Cookies.get("closeModal")); + const [closeModal, setCloseModal] = useState(Cookies.get('closeModal')) useEffect(() => { if (closeModal) { - Cookies.set("closeModal", true); + Cookies.set('closeModal', true) } else { - Cookies.remove("closeModal"); + Cookies.remove('closeModal') } - }, [closeModal]); + }, [closeModal]) return (
    @@ -54,16 +54,16 @@ export default function Layout({ meta, children, subdomain }) { - {subdomain != "demo" && } + {subdomain != 'demo' && }
    - {" "} + {' '}
    - {subdomain == "demo" ? ( + {subdomain == 'demo' ? ( <> @@ -128,17 +128,17 @@ export default function Layout({ meta, children, subdomain }) {
    {children}
    - {subdomain == "demo" && ( + {subdomain == 'demo' && (
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/components/sites/Loader.js b/solutions/platforms-slate-supabase/components/sites/Loader.js index 3c8b38187b..10fac91888 100644 --- a/solutions/platforms-slate-supabase/components/sites/Loader.js +++ b/solutions/platforms-slate-supabase/components/sites/Loader.js @@ -11,5 +11,5 @@ export default function Loader() {
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/lib/save-image.js b/solutions/platforms-slate-supabase/lib/save-image.js index f2df980d0c..46c8188ee5 100644 --- a/solutions/platforms-slate-supabase/lib/save-image.js +++ b/solutions/platforms-slate-supabase/lib/save-image.js @@ -1,14 +1,14 @@ -import { decode } from "blurhash"; -import { getImgFromArr } from "array-to-image"; +import { decode } from 'blurhash' +import { getImgFromArr } from 'array-to-image' const saveImage = async (imageData, data, setData) => { - const res = await fetch(`/api/blurhash?url=${imageData.url}`); + const res = await fetch(`/api/blurhash?url=${imageData.url}`) if (res.ok) { - const blurhash = await res.json(); - const pixels = decode(blurhash.hash, 32, 32); - const image = getImgFromArr(pixels, 32, 32); - setData({ ...data, image: imageData.url, imageBlurhash: image.src }); + const blurhash = await res.json() + const pixels = decode(blurhash.hash, 32, 32) + const image = getImgFromArr(pixels, 32, 32) + setData({ ...data, image: imageData.url, imageBlurhash: image.src }) } -}; +} -export default saveImage; +export default saveImage diff --git a/solutions/platforms-slate-supabase/lib/supabase.js b/solutions/platforms-slate-supabase/lib/supabase.js index 88eecbf7c6..7838658094 100644 --- a/solutions/platforms-slate-supabase/lib/supabase.js +++ b/solutions/platforms-slate-supabase/lib/supabase.js @@ -1,8 +1,8 @@ -import { createClient } from "@supabase/supabase-js"; +import { createClient } from '@supabase/supabase-js' const supabase = createClient( process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY -); +) -export default supabase; +export default supabase diff --git a/solutions/platforms-slate-supabase/lib/twitter-media.js b/solutions/platforms-slate-supabase/lib/twitter-media.js index 138fc98099..6defcf58f3 100644 --- a/solutions/platforms-slate-supabase/lib/twitter-media.js +++ b/solutions/platforms-slate-supabase/lib/twitter-media.js @@ -7,22 +7,22 @@ export const getTwitterMedia = async (id) => { Authorization: `Bearer ${process.env.TWITTER_AUTH_TOKEN}`, }, } - ); - const data = await response.json(); - const videoData = data.extended_entities.media[0].video_info; + ) + const data = await response.json() + const videoData = data.extended_entities.media[0].video_info // filter for only MP4 videos const mp4VideosOnly = videoData.variants.filter( - (variant) => variant.content_type === "video/mp4" - ); + (variant) => variant.content_type === 'video/mp4' + ) // get the video with the best bitrate const bestVideoBitrate = mp4VideosOnly.reduce(function (prev, current) { - return prev.bitrate > current.bitrate ? prev : current; - }); + return prev.bitrate > current.bitrate ? prev : current + }) - return bestVideoBitrate; + return bestVideoBitrate } catch (error) { - console.log(id, error); + console.log(id, error) } -}; +} diff --git a/solutions/platforms-slate-supabase/lib/twitter.js b/solutions/platforms-slate-supabase/lib/twitter.js index 9734dcc5b2..d436455bcf 100644 --- a/solutions/platforms-slate-supabase/lib/twitter.js +++ b/solutions/platforms-slate-supabase/lib/twitter.js @@ -1,18 +1,18 @@ -import querystring from "querystring"; -import { getTwitterMedia } from "./twitter-media"; -import { truncate } from "./util"; +import querystring from 'querystring' +import { getTwitterMedia } from './twitter-media' +import { truncate } from './util' export const getTweets = async (id) => { const queryParams = querystring.stringify({ expansions: - "author_id,attachments.media_keys,referenced_tweets.id,referenced_tweets.id.author_id,attachments.poll_ids", - "tweet.fields": - "attachments,author_id,public_metrics,created_at,id,in_reply_to_user_id,referenced_tweets,text,entities", - "user.fields": "id,name,profile_image_url,protected,url,username,verified", - "media.fields": - "duration_ms,height,media_key,preview_image_url,type,url,width,public_metrics", - "poll.fields": "duration_minutes,end_datetime,id,options,voting_status", - }); + 'author_id,attachments.media_keys,referenced_tweets.id,referenced_tweets.id.author_id,attachments.poll_ids', + 'tweet.fields': + 'attachments,author_id,public_metrics,created_at,id,in_reply_to_user_id,referenced_tweets,text,entities', + 'user.fields': 'id,name,profile_image_url,protected,url,username,verified', + 'media.fields': + 'duration_ms,height,media_key,preview_image_url,type,url,width,public_metrics', + 'poll.fields': 'duration_minutes,end_datetime,id,options,voting_status', + }) const response = await fetch( `https://api.twitter.com/2/tweets/${id}?${queryParams}`, @@ -21,67 +21,67 @@ export const getTweets = async (id) => { Authorization: `Bearer ${process.env.TWITTER_AUTH_TOKEN}`, }, } - ); + ) - const tweet = await response.json(); + const tweet = await response.json() const getAuthorInfo = (author_id) => { - return tweet.includes.users.find((user) => user.id === author_id); - }; + return tweet.includes.users.find((user) => user.id === author_id) + } const getReferencedTweets = (mainTweet) => { return ( mainTweet?.referenced_tweets?.map((referencedTweet) => { const fullReferencedTweet = tweet.includes.tweets.find( (tweet) => tweet.id === referencedTweet.id - ); + ) return { type: referencedTweet.type, author: getAuthorInfo(fullReferencedTweet.author_id), ...fullReferencedTweet, - }; + } }) || [] - ); - }; + ) + } // function to distinguish between external URLs and external t.co links and internal t.co links // (e.g. images, videos, gifs, quote tweets) and remove/replace them accordingly const getExternalUrls = (tweet) => { - const externalURLs = tweet?.entities?.urls; - const mappings = {}; + const externalURLs = tweet?.entities?.urls + const mappings = {} if (externalURLs) { externalURLs.map((url) => { mappings[`${url.url}`] = - !url.display_url.startsWith("pic.twitter.com") && - !url.display_url.startsWith("twitter.com") + !url.display_url.startsWith('pic.twitter.com') && + !url.display_url.startsWith('twitter.com') ? url.expanded_url - : ""; - }); + : '' + }) } - var processedText = tweet?.text; + var processedText = tweet?.text Object.entries(mappings).map(([k, v], i) => { - processedText = processedText.replace(k, v); - }); - return processedText; - }; - if (tweet.data) tweet.data.text = getExternalUrls(tweet?.data); // removing/replacing t.co links for main tweet + processedText = processedText.replace(k, v) + }) + return processedText + } + if (tweet.data) tweet.data.text = getExternalUrls(tweet?.data) // removing/replacing t.co links for main tweet tweet?.includes?.tweets?.map((twt) => { // removing/replacing t.co links for referenced tweets - twt.text = getExternalUrls(twt); - }); + twt.text = getExternalUrls(twt) + }) const media = tweet.data?.attachments?.media_keys?.map((key) => tweet.includes.media.find((media) => media.media_key === key) - ); + ) - const referenced_tweets = getReferencedTweets(tweet.data); + const referenced_tweets = getReferencedTweets(tweet.data) return { ...tweet.data, media: media || [], video: - media && (media[0].type == "video" || media[0].type == "animated_gif") + media && (media[0].type == 'video' || media[0].type == 'animated_gif') ? await getTwitterMedia(id) : null, polls: tweet?.includes?.polls, @@ -91,5 +91,5 @@ export const getTweets = async (id) => { : tweet.data?.entities?.urls[0], referenced_tweets: referenced_tweets, author: getAuthorInfo(tweet.data?.author_id), - }; -}; + } +} diff --git a/solutions/platforms-slate-supabase/lib/useRequireAuth.js b/solutions/platforms-slate-supabase/lib/useRequireAuth.js index 7537e55ac0..a38f9779a5 100644 --- a/solutions/platforms-slate-supabase/lib/useRequireAuth.js +++ b/solutions/platforms-slate-supabase/lib/useRequireAuth.js @@ -1,20 +1,20 @@ -import { useSession } from "next-auth/react"; -import { useEffect } from "react"; -import { useRouter } from "next/router"; +import { useSession } from 'next-auth/react' +import { useEffect } from 'react' +import { useRouter } from 'next/router' function useRequireAuth() { - const { data: session } = useSession(); + const { data: session } = useSession() - const router = useRouter(); + const router = useRouter() // If auth.user is false that means we're not // logged in and should redirect. useEffect(() => { - if (!session && typeof session != "undefined") { - router.push(`/login`); + if (!session && typeof session != 'undefined') { + router.push(`/login`) } - }, [session, router]); + }, [session, router]) - return session; + return session } -export default useRequireAuth; +export default useRequireAuth diff --git a/solutions/platforms-slate-supabase/lib/util.js b/solutions/platforms-slate-supabase/lib/util.js index 06f39fb011..f099247560 100644 --- a/solutions/platforms-slate-supabase/lib/util.js +++ b/solutions/platforms-slate-supabase/lib/util.js @@ -1,11 +1,11 @@ export const capitalize = (s) => { - if (typeof s !== "string") return ""; - return s.charAt(0).toUpperCase() + s.slice(1); -}; + if (typeof s !== 'string') return '' + return s.charAt(0).toUpperCase() + s.slice(1) +} export const truncate = (str, num) => { if (str.length <= num) { - return str; + return str } - return str.slice(0, num) + "..."; -}; + return str.slice(0, num) + '...' +} diff --git a/solutions/platforms-slate-supabase/next.config.js b/solutions/platforms-slate-supabase/next.config.js index 063ee328ad..f3cc97c5d9 100644 --- a/solutions/platforms-slate-supabase/next.config.js +++ b/solutions/platforms-slate-supabase/next.config.js @@ -1,11 +1,11 @@ module.exports = { images: { domains: [ - "res.cloudinary.com", - "abs.twimg.com", - "pbs.twimg.com", - "api.producthunt.com", - 'avatars.githubusercontent.com' + 'res.cloudinary.com', + 'abs.twimg.com', + 'pbs.twimg.com', + 'api.producthunt.com', + 'avatars.githubusercontent.com', ], }, -}; +} diff --git a/solutions/platforms-slate-supabase/pages/_app.js b/solutions/platforms-slate-supabase/pages/_app.js index 2c80623a16..f72dad678d 100644 --- a/solutions/platforms-slate-supabase/pages/_app.js +++ b/solutions/platforms-slate-supabase/pages/_app.js @@ -1,6 +1,6 @@ -import "@/styles/globals.css"; -import { SessionProvider } from "next-auth/react"; -import PlausibleProvider from "next-plausible"; +import '@/styles/globals.css' +import { SessionProvider } from 'next-auth/react' +import PlausibleProvider from 'next-plausible' export default function App({ Component, @@ -12,5 +12,5 @@ export default function App({ - ); + ) } diff --git a/solutions/platforms-slate-supabase/pages/_sites/[site]/[slug].js b/solutions/platforms-slate-supabase/pages/_sites/[site]/[slug].js index 5f01e97a26..d378ed0840 100644 --- a/solutions/platforms-slate-supabase/pages/_sites/[site]/[slug].js +++ b/solutions/platforms-slate-supabase/pages/_sites/[site]/[slug].js @@ -1,79 +1,79 @@ -import React from "react"; -import supabase from "@/lib/supabase"; -import Layout from "@/components/sites/Layout"; -import BlurImage from "@/components/BlurImage"; -import Date from "@/components/Date"; -import { Text } from "slate"; -import Highlight from "react-highlight"; -import { useRouter } from "next/router"; -import Loader from "@/components/sites/Loader"; +import React from 'react' +import supabase from '@/lib/supabase' +import Layout from '@/components/sites/Layout' +import BlurImage from '@/components/BlurImage' +import Date from '@/components/Date' +import { Text } from 'slate' +import Highlight from 'react-highlight' +import { useRouter } from 'next/router' +import Loader from '@/components/sites/Loader' const serialize = (node) => { if (Text.isText(node)) { if (node.code) { - return {node.text}; + return {node.text} } - if (node["heading-one"]) { + if (node['heading-one']) { return (

    {node.text}

    - ); + ) } if (node.bold && node.italic) { - return

    {node.text}

    ; + return

    {node.text}

    } if (node.bold) { - return

    {node.text}

    ; + return

    {node.text}

    } if (node.italic) { - return

    {node.text}

    ; + return

    {node.text}

    } - if (node["heading-two"]) { - return

    {node.text}

    ; + if (node['heading-two']) { + return

    {node.text}

    } - return node.text; + return node.text } - const children = node?.children.map((n) => serialize(n)); + const children = node?.children.map((n) => serialize(n)) switch (node.type) { - case "block-quote": - return
    {children}
    ; - case "italic": - return {children}; - case "underline": - return

    {children}

    ; - - case "heading-one": - return

    {children}

    ; - case "heading-two": - return

    {children}

    ; - case "code": - return {children}; - - case "list-item": - return
  • {children}
  • ; - case "numbered-list": - return
      {children}
    ; + case 'block-quote': + return
    {children}
    + case 'italic': + return {children} + case 'underline': + return

    {children}

    + + case 'heading-one': + return

    {children}

    + case 'heading-two': + return

    {children}

    + case 'code': + return {children} + + case 'list-item': + return
  • {children}
  • + case 'numbered-list': + return
      {children}
    default: - return

    {children}

    ; + return

    {children}

    } -}; +} export default function Post(props) { - console.log(props); - const router = useRouter(); + console.log(props) + const router = useRouter() if (router.isFallback) { - return ; + return } - const data = JSON.parse(props.stringifiedData); - console.log(data); + const data = JSON.parse(props.stringifiedData) + console.log(data) // const adjacentPosts = JSON.parse(props.stringifiedAdjacentPosts); const meta = { @@ -81,8 +81,8 @@ export default function Post(props) { description: data.description, ogUrl: `https://${data.site.subdomain}.vercel.im/${data.slug}`, ogImage: data.image, - logo: "/logo.png", - }; + logo: '/logo.png', + } return ( @@ -136,41 +136,41 @@ export default function Post(props) { )} */} - ); + ) } export async function getStaticPaths() { - const { data } = await supabase.from("post").select( + const { data } = await supabase.from('post').select( `slug, site ( subdomain, customDomain ) ` - ); + ) return { paths: data.flatMap((post) => { - const params = []; + const params = [] if (post.site.subdomain) { - params.push({ params: { site: post.site.subdomain, slug: post.slug } }); + params.push({ params: { site: post.site.subdomain, slug: post.slug } }) } if (post.site.customDomain) { params.push({ params: { site: post.site.customDomain, slug: post.slug }, - }); + }) } - return params; + return params }), fallback: true, - }; + } } export async function getStaticProps({ params: { site, slug } }) { const { data } = await supabase - .from("post") + .from('post') .select( `*, site ( @@ -179,10 +179,10 @@ export async function getStaticProps({ params: { site, slug } }) { ) ` ) - .eq("slug", slug); + .eq('slug', slug) if (data.length === 0) { - return { notFound: true, revalidate: 10 }; + return { notFound: true, revalidate: 10 } } return { @@ -190,5 +190,5 @@ export async function getStaticProps({ params: { site, slug } }) { stringifiedData: JSON.stringify(data[0]), }, revalidate: 10, - }; + } } diff --git a/solutions/platforms-slate-supabase/pages/_sites/[site]/index.js b/solutions/platforms-slate-supabase/pages/_sites/[site]/index.js index c85973c270..0d05ed2010 100644 --- a/solutions/platforms-slate-supabase/pages/_sites/[site]/index.js +++ b/solutions/platforms-slate-supabase/pages/_sites/[site]/index.js @@ -1,19 +1,19 @@ -import Layout from "@/components/sites/Layout"; -import supabase from "@/lib/supabase"; -import { useRouter } from "next/router"; -import BlurImage from "@/components/BlurImage"; -import BlogCard from "@/components/BlogCard"; -import Loader from "@/components/sites/Loader"; -import Date from "@/components/Date"; -import Link from "next/link"; +import Layout from '@/components/sites/Layout' +import supabase from '@/lib/supabase' +import { useRouter } from 'next/router' +import BlurImage from '@/components/BlurImage' +import BlogCard from '@/components/BlogCard' +import Loader from '@/components/sites/Loader' +import Date from '@/components/Date' +import Link from 'next/link' export default function Index(props) { - const router = useRouter(); + const router = useRouter() if (router.isFallback) { - return ; + return } - const data = JSON.parse(props.data); + const data = JSON.parse(props.data) const meta = { title: data.name, @@ -22,8 +22,8 @@ export default function Index(props) { ? data.customDomain : `https://${data.subdomain}.vercel.im`, ogImage: data.image, - logo: "/logo.png", - }; + logo: '/logo.png', + } return ( @@ -53,7 +53,7 @@ export default function Index(props) {

    {data.userId} -

    +

    @@ -89,64 +89,62 @@ export default function Index(props) {

    )} - ); + ) } export async function getStaticPaths() { - console.log("hello"); + console.log('hello') - const { data } = await supabase - .from("site") - .select("subdomain, customDomain"); + const { data } = await supabase.from('site').select('subdomain, customDomain') const subdomains = data .filter((site) => site.subdomain) - .map((site) => site.subdomain); + .map((site) => site.subdomain) const domains = data .filter((site) => site.customDomain) - .map((site) => site.customDomain); + .map((site) => site.customDomain) - const allPaths = [...subdomains, ...domains]; + const allPaths = [...subdomains, ...domains] return { paths: allPaths.map((path) => { - return { params: { site: path } }; + return { params: { site: path } } }), fallback: true, - }; + } } export async function getStaticProps({ params: { site } }) { let filter = { subdomain: site, - }; - if (site.includes(".")) { + } + if (site.includes('.')) { filter = { customDomain: site, - }; + } } - const eq = site.includes(".") ? "customDomain" : "subdomain"; + const eq = site.includes('.') ? 'customDomain' : 'subdomain' - const { data } = await supabase.from("site").select("*").eq(eq, site); + const { data } = await supabase.from('site').select('*').eq(eq, site) if (data.length === 0) { - return { notFound: true, revalidate: 10 }; + return { notFound: true, revalidate: 10 } } const { data: posts } = await supabase - .from("post") - .select("*") - .eq("siteId", data[0].id); + .from('post') + .select('*') + .eq('siteId', data[0].id) const siteWithPosts = { ...data[0], posts, - }; + } return { props: { data: JSON.stringify(siteWithPosts), }, revalidate: 10, - }; + } } diff --git a/solutions/platforms-slate-supabase/pages/api/add-domain.js b/solutions/platforms-slate-supabase/pages/api/add-domain.js index 8b7169f27a..9fd735f17e 100755 --- a/solutions/platforms-slate-supabase/pages/api/add-domain.js +++ b/solutions/platforms-slate-supabase/pages/api/add-domain.js @@ -1,7 +1,7 @@ -import supabase from "@/lib/supabase"; +import supabase from '@/lib/supabase' export default async function addDomain(req, res) { - const { domain, siteId } = req.query; + const { domain, siteId } = req.query const response = await fetch( `https://api.vercel.com/v8/projects/${process.env.VERCEL_PROJECT_ID}/domains?teamId=${process.env.VERCEL_TEAM_ID}`, @@ -9,23 +9,23 @@ export default async function addDomain(req, res) { body: `{\n "name": "${domain}"\n}`, headers: { Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, - method: "POST", + method: 'POST', } - ); + ) - const data = await response.json(); + const data = await response.json() - if (data.error?.code == "forbidden") { - res.status(403).end(); // domain is already owned by another team but you can request delegation to access it - } else if (data.error?.code == "domain_taken") { - res.status(409).end(); // domain is already being used by a different project + if (data.error?.code == 'forbidden') { + res.status(403).end() // domain is already owned by another team but you can request delegation to access it + } else if (data.error?.code == 'domain_taken') { + res.status(409).end() // domain is already being used by a different project } else { await supabase - .from("sites") + .from('sites') .update({ customDomain: domain }) - .match({ id: siteId }); - res.status(200).end(); + .match({ id: siteId }) + res.status(200).end() } } diff --git a/solutions/platforms-slate-supabase/pages/api/auth/[...nextauth].js b/solutions/platforms-slate-supabase/pages/api/auth/[...nextauth].js index a26870685c..fe22aa3d6e 100755 --- a/solutions/platforms-slate-supabase/pages/api/auth/[...nextauth].js +++ b/solutions/platforms-slate-supabase/pages/api/auth/[...nextauth].js @@ -1,5 +1,5 @@ -import NextAuth from "next-auth"; -import Github from "next-auth/providers/github"; +import NextAuth from 'next-auth' +import Github from 'next-auth/providers/github' const options = { providers: [ @@ -9,6 +9,6 @@ const options = { }), ], secret: process.env.SECRET, -}; +} -export default (req, res) => NextAuth(req, res, options); +export default (req, res) => NextAuth(req, res, options) diff --git a/solutions/platforms-slate-supabase/pages/api/blurhash.js b/solutions/platforms-slate-supabase/pages/api/blurhash.js index 1f71133aca..737b1043fb 100755 --- a/solutions/platforms-slate-supabase/pages/api/blurhash.js +++ b/solutions/platforms-slate-supabase/pages/api/blurhash.js @@ -1,8 +1,8 @@ -import { getPlaiceholder } from "plaiceholder"; +import { getPlaiceholder } from 'plaiceholder' export default async function blurhash(req, res) { - const { url } = req.query; - const { blurhash } = await getPlaiceholder(url); + const { url } = req.query + const { blurhash } = await getPlaiceholder(url) - res.status(200).json(blurhash); + res.status(200).json(blurhash) } diff --git a/solutions/platforms-slate-supabase/pages/api/check-domain.js b/solutions/platforms-slate-supabase/pages/api/check-domain.js index 2df6d82c17..8bd04a5556 100755 --- a/solutions/platforms-slate-supabase/pages/api/check-domain.js +++ b/solutions/platforms-slate-supabase/pages/api/check-domain.js @@ -1,20 +1,20 @@ export default async function checkDomain(req, res) { - const { domain } = req.query; + const { domain } = req.query const response = await fetch( `https://api.vercel.com/v6/domains/${domain}/config?teamId=${process.env.VERCEL_TEAM_ID}`, { - method: "GET", + method: 'GET', headers: { Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, } - ); + ) - const data = await response.json(); + const data = await response.json() - const valid = data?.configuredBy ? true : false; + const valid = data?.configuredBy ? true : false - res.status(200).json(valid); + res.status(200).json(valid) } diff --git a/solutions/platforms-slate-supabase/pages/api/check-subdomain.js b/solutions/platforms-slate-supabase/pages/api/check-subdomain.js index be5d14dbcd..8d6f6f6544 100755 --- a/solutions/platforms-slate-supabase/pages/api/check-subdomain.js +++ b/solutions/platforms-slate-supabase/pages/api/check-subdomain.js @@ -1,15 +1,15 @@ -import supabase from "@/lib/supabase"; +import supabase from '@/lib/supabase' export default async function checkSubdomain(req, res) { - const { subdomain } = req.query; - const sub = subdomain.replace(/[^a-zA-Z0-9/-]+/g, ""); + const { subdomain } = req.query + const sub = subdomain.replace(/[^a-zA-Z0-9/-]+/g, '') const { data } = await supabase - .from("site") - .select("subdomain") - .eq("subdomain", sub); + .from('site') + .select('subdomain') + .eq('subdomain', sub) - const available = data.length === 0 && sub.length !== 0; + const available = data.length === 0 && sub.length !== 0 - res.status(200).json(available); + res.status(200).json(available) } diff --git a/solutions/platforms-slate-supabase/pages/api/post.js b/solutions/platforms-slate-supabase/pages/api/post.js index ac0bbd1542..d288aab547 100755 --- a/solutions/platforms-slate-supabase/pages/api/post.js +++ b/solutions/platforms-slate-supabase/pages/api/post.js @@ -1,71 +1,68 @@ -import supabase from "@/lib/supabase"; -import cuid from 'cuid'; +import supabase from '@/lib/supabase' +import cuid from 'cuid' export default async function post(req, res) { switch (req.method) { - case "GET": { - const { postId, siteId, published } = req.query; + case 'GET': { + const { postId, siteId, published } = req.query if (postId) { // get individual post const { data: [post], - } = await supabase.from("post").select("*").eq("id", postId); - + } = await supabase.from('post').select('*').eq('id', postId) const { data } = await supabase - .from("site") - .select("*") - .eq("id", post.siteId); - + .from('site') + .select('*') + .eq('id', post.siteId) - res.status(200).json({ ...post, site: data[0] }); + res.status(200).json({ ...post, site: data[0] }) } else { // get all posts const { data: posts } = await supabase - .from("post") - .select("*") - .eq("siteId", siteId); - + .from('post') + .select('*') + .eq('siteId', siteId) const { data: siteData } = await supabase - .from("site") - .select("*") - .eq("id", siteId); + .from('site') + .select('*') + .eq('id', siteId) - res.status(200).json({ posts, site: siteData[0] }); + res.status(200).json({ posts, site: siteData[0] }) } - return; + return } - case "POST": { + case 'POST': { // create post - const { siteId } = req.query; - const { data } = await supabase.from("post").upsert({ + const { siteId } = req.query + const { data } = await supabase.from('post').upsert({ image: `/placeholder.png`, imageBlurhash: - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAoJJREFUWEfFl4lu4zAMRO3cx/9/au6reMaOdkxTTl0grQFCRoqaT+SQotq2bV9N8rRt28xms87m83l553eZ/9vr9Wpkz+ezkT0ej+6dv1X81AFw7M4FBACPVn2c1Z3zLgDeJwHgeLFYdAARYioAEAKJEG2WAjl3gCwNYymQQ9b7/V4spmIAwO6Wy2VnAMikBWlDURBELf8CuN1uHQSrPwMAHK5WqwFELQ01AIXdAa7XawfAb3p6AOwK5+v1ugAoEq4FRSFLgavfQ49jAGQpAE5wjgGCeRrGdBArwHOPcwFcLpcGU1X0IsBuN5tNgYhaiFFwHTiAwq8I+O5xfj6fOz38K+X/fYAdb7fbAgFAjIJ6Aav3AYlQ6nfnDoDz0+lUxNiLALvf7XaDNGQ6GANQBKR85V27B4D3QQRw7hGIYlQKWGM79hSweyCUe1blXhEAogfABwHAXAcqSYkxCtHLUK3XBajSc4Dj8dilAeiSAgD2+30BAEKV4GKcAuDqB4TdYwBgPQByCgApUBoE4EJUGvxUjF3Q69/zLw3g/HA45ABKgdIQu+JPIyDnisCfAxAFNFM0EFNQ64gfS0EUoQP8ighrZSjn3oziZEQpauyKbfjbZchHUL/3AS/Dd30gAkxuRACgfO+EWQW8qwI1o+wseNuKcQiESjALvwNoMI0TcRzD4lFcPYwIM+JTF5x6HOs8yI7jeB5oKhpMRFH9UwaSCDB2Jmg4rc6E2TT0biIaG0rQhNqyhpHBcayTTSXH6vcDL7/sdqRK8LkwTsU499E8vRcAojHcZ4AxABdilgrp4lsXk8oVqgwh7+6H3phqd8J0Kk4vbx/+sZqCD/vNLya/5dT9fAH8g1WdNGgwbQAAAABJRU5ErkJggg==", + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAoJJREFUWEfFl4lu4zAMRO3cx/9/au6reMaOdkxTTl0grQFCRoqaT+SQotq2bV9N8rRt28xms87m83l553eZ/9vr9Wpkz+ezkT0ej+6dv1X81AFw7M4FBACPVn2c1Z3zLgDeJwHgeLFYdAARYioAEAKJEG2WAjl3gCwNYymQQ9b7/V4spmIAwO6Wy2VnAMikBWlDURBELf8CuN1uHQSrPwMAHK5WqwFELQ01AIXdAa7XawfAb3p6AOwK5+v1ugAoEq4FRSFLgavfQ49jAGQpAE5wjgGCeRrGdBArwHOPcwFcLpcGU1X0IsBuN5tNgYhaiFFwHTiAwq8I+O5xfj6fOz38K+X/fYAdb7fbAgFAjIJ6Aav3AYlQ6nfnDoDz0+lUxNiLALvf7XaDNGQ6GANQBKR85V27B4D3QQRw7hGIYlQKWGM79hSweyCUe1blXhEAogfABwHAXAcqSYkxCtHLUK3XBajSc4Dj8dilAeiSAgD2+30BAEKV4GKcAuDqB4TdYwBgPQByCgApUBoE4EJUGvxUjF3Q69/zLw3g/HA45ABKgdIQu+JPIyDnisCfAxAFNFM0EFNQ64gfS0EUoQP8ighrZSjn3oziZEQpauyKbfjbZchHUL/3AS/Dd30gAkxuRACgfO+EWQW8qwI1o+wseNuKcQiESjALvwNoMI0TcRzD4lFcPYwIM+JTF5x6HOs8yI7jeB5oKhpMRFH9UwaSCDB2Jmg4rc6E2TT0biIaG0rQhNqyhpHBcayTTSXH6vcDL7/sdqRK8LkwTsU499E8vRcAojHcZ4AxABdilgrp4lsXk8oVqgwh7+6H3phqd8J0Kk4vbx/+sZqCD/vNLya/5dT9fAH8g1WdNGgwbQAAAABJRU5ErkJggg==', siteId, slug: cuid(), content: [ { - type: "paragraph", + type: 'paragraph', children: [{ text: `Write about your post` }], }, ], - }); + }) - res.status(200).json({ postId: data[0].id }); - return; + res.status(200).json({ postId: data[0].id }) + return } - case "DELETE": { + case 'DELETE': { // delete post - const { postId } = req.query; - await supabase.from("post").delete().match({ id: postId }); + const { postId } = req.query + await supabase.from('post').delete().match({ id: postId }) - res.status(200).end(); - return; + res.status(200).end() + return } - case "PUT": { + case 'PUT': { // publish post, update post content, update post settings const { id, @@ -76,9 +73,9 @@ export default async function post(req, res) { image, imageBlurhash, published, - } = req.body; + } = req.body - const { data } = await supabase.from("post").upsert({ + const { data } = await supabase.from('post').upsert({ title, description, content, @@ -87,12 +84,12 @@ export default async function post(req, res) { imageBlurhash, published, id, - }); + }) - res.status(200).json(data[0]); + res.status(200).json(data[0]) } default: - res.status(405).end(); - return; + res.status(405).end() + return } } diff --git a/solutions/platforms-slate-supabase/pages/api/remove-domain.js b/solutions/platforms-slate-supabase/pages/api/remove-domain.js index 6d16f11bd6..84e16ebfb6 100755 --- a/solutions/platforms-slate-supabase/pages/api/remove-domain.js +++ b/solutions/platforms-slate-supabase/pages/api/remove-domain.js @@ -1,7 +1,7 @@ -import supabase from "@/lib/supabase"; +import supabase from '@/lib/supabase' export default async function removeDomain(req, res) { - const { domain, siteId } = req.query; + const { domain, siteId } = req.query const response = await fetch( `https://api.vercel.com/v8/projects/${process.env.VERCEL_PROJECT_ID}/domains/${domain}?teamId=${process.env.VERCEL_TEAM_ID}`, @@ -9,15 +9,15 @@ export default async function removeDomain(req, res) { headers: { Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, }, - method: "DELETE", + method: 'DELETE', } - ); + ) - await response.json(); + await response.json() await supabase - .from("sites") + .from('sites') .update({ customDomain: null }) - .match({ id: siteId }); + .match({ id: siteId }) - res.status(200).end(); + res.status(200).end() } diff --git a/solutions/platforms-slate-supabase/pages/api/request-delegation.js b/solutions/platforms-slate-supabase/pages/api/request-delegation.js index 8e4d4d6512..29b1feccce 100755 --- a/solutions/platforms-slate-supabase/pages/api/request-delegation.js +++ b/solutions/platforms-slate-supabase/pages/api/request-delegation.js @@ -1,20 +1,20 @@ export default async function requestDelegation(req, res) { - const { domain } = req.query; + const { domain } = req.query const response = await fetch( `https://api.vercel.com/v6/domains/${domain}/request-delegation?teamId=${process.env.VERCEL_TEAM_ID}`, { headers: { Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`, - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, - method: "POST", + method: 'POST', } - ); + ) if (response.ok) { - res.status(200).end(); + res.status(200).end() } else { - res.status(403).end(); + res.status(403).end() } } diff --git a/solutions/platforms-slate-supabase/pages/api/save-settings.js b/solutions/platforms-slate-supabase/pages/api/save-settings.js index 56236131f1..e6eaceb8e8 100755 --- a/solutions/platforms-slate-supabase/pages/api/save-settings.js +++ b/solutions/platforms-slate-supabase/pages/api/save-settings.js @@ -1,16 +1,14 @@ - export default async function SaveSiteSettings(req, res) { - const data = JSON.parse(req.body); + const data = JSON.parse(req.body) await supabase - .from("sites") - .update({ - name: data.name, - email: data.email, - image: data.image, - }) - .match({ id: data.id }); - - - res.status(200).json(response); + .from('sites') + .update({ + name: data.name, + email: data.email, + image: data.image, + }) + .match({ id: data.id }) + + res.status(200).json(response) } diff --git a/solutions/platforms-slate-supabase/pages/api/site.js b/solutions/platforms-slate-supabase/pages/api/site.js index 43e8af07a5..a129ba8c9c 100755 --- a/solutions/platforms-slate-supabase/pages/api/site.js +++ b/solutions/platforms-slate-supabase/pages/api/site.js @@ -1,58 +1,58 @@ -import supabase from "@/lib/supabase"; +import supabase from '@/lib/supabase' export default async function site(req, res) { switch (req.method) { - case "GET": { - const { userId, siteId } = req.query; + case 'GET': { + const { userId, siteId } = req.query if (siteId) { // get individual site - const { siteId } = req.query; + const { siteId } = req.query const { data } = await supabase - .from("site") - .select("*") - .eq("id", siteId); + .from('site') + .select('*') + .eq('id', siteId) - res.status(200).json(data[0]); + res.status(200).json(data[0]) } else { // get all sites const { data } = await supabase - .from("site") - .select("*") - .eq("userId", userId); - res.status(200).json(data); + .from('site') + .select('*') + .eq('userId', userId) + res.status(200).json(data) } - - return; + + return } - case "POST": { + case 'POST': { // create site - const { name, subdomain, description, userId } = req.body; - const sub = subdomain.replace(/[^a-zA-Z0-9/-]+/g, ""); + const { name, subdomain, description, userId } = req.body + const sub = subdomain.replace(/[^a-zA-Z0-9/-]+/g, '') - const { data } = await supabase.from("site").upsert({ + const { data } = await supabase.from('site').upsert({ name, description, subdomain: sub.length > 0 ? sub : cuid(), - logo: "/logo.png", + logo: '/logo.png', image: `/placeholder.png`, userId, - }); + }) - res.status(200).json({ siteId: data[0].id }); - return; + res.status(200).json({ siteId: data[0].id }) + return } - case "DELETE": { + case 'DELETE': { // delete site - const { siteId } = req.query; + const { siteId } = req.query - await supabase.from("post").delete().match({ siteId: siteId }); - await supabase.from("site").delete().match({ id: siteId }); + await supabase.from('post').delete().match({ siteId: siteId }) + await supabase.from('site').delete().match({ id: siteId }) - res.status(200).end(); - return; + res.status(200).end() + return } - case "PUT": { + case 'PUT': { // save site settings let { id, @@ -62,25 +62,25 @@ export default async function site(req, res) { subdomain, image, imageBlurhash, - } = req.body; + } = req.body // processing subdomain - const sub = subdomain.replace(/[^a-zA-Z0-9/-]+/g, ""); - subdomain = sub.length > 0 ? sub : currentSubdomain; + const sub = subdomain.replace(/[^a-zA-Z0-9/-]+/g, '') + subdomain = sub.length > 0 ? sub : currentSubdomain - const { data } = await supabase.from("site").upsert({ + const { data } = await supabase.from('site').upsert({ name, description, subdomain, image, imageBlurhash, id, - }); + }) - res.status(200).json(data[0]); + res.status(200).json(data[0]) } default: - res.status(405).end(); - return; + res.status(405).end() + return } } diff --git a/solutions/platforms-slate-supabase/pages/app/index.js b/solutions/platforms-slate-supabase/pages/app/index.js index ab2ca2199d..011a81d481 100644 --- a/solutions/platforms-slate-supabase/pages/app/index.js +++ b/solutions/platforms-slate-supabase/pages/app/index.js @@ -1,55 +1,55 @@ -import { useState, useEffect } from "react"; -import Layout from "@/components/app/Layout"; -import BlurImage from "@/components/BlurImage"; -import Modal from "@/components/Modal"; -import LoadingDots from "@/components/app/loading-dots"; -import Link from "next/link"; -import { useSession } from "next-auth/react"; -import { useRouter } from "next/router"; -import useSWR from "swr"; -import { useDebounce } from "use-debounce"; +import { useState, useEffect } from 'react' +import Layout from '@/components/app/Layout' +import BlurImage from '@/components/BlurImage' +import Modal from '@/components/Modal' +import LoadingDots from '@/components/app/loading-dots' +import Link from 'next/link' +import { useSession } from 'next-auth/react' +import { useRouter } from 'next/router' +import useSWR from 'swr' +import { useDebounce } from 'use-debounce' const fetcher = (...args) => { - console.log("fetching", ...args); - return fetch(...args).then((res) => res.json()); -}; + console.log('fetching', ...args) + return fetch(...args).then((res) => res.json()) +} export default function AppIndex() { - const [showModal, setShowModal] = useState(false); - const [creatingSite, setCreatingSite] = useState(false); - const [subdomain, setSubdomain] = useState(""); - const [debouncedSubdomain] = useDebounce(subdomain, 1500); - const [error, setError] = useState(null); + const [showModal, setShowModal] = useState(false) + const [creatingSite, setCreatingSite] = useState(false) + const [subdomain, setSubdomain] = useState('') + const [debouncedSubdomain] = useDebounce(subdomain, 1500) + const [error, setError] = useState(null) useEffect(async () => { if (debouncedSubdomain.length > 0) { const response = await fetch( `/api/check-subdomain?subdomain=${debouncedSubdomain}` - ); - const available = await response.json(); + ) + const available = await response.json() if (available) { - setError(null); + setError(null) } else { - setError(`${debouncedSubdomain}.vercel.im`); + setError(`${debouncedSubdomain}.vercel.im`) } } - }, [debouncedSubdomain]); + }, [debouncedSubdomain]) - const router = useRouter(); + const router = useRouter() - const { data: session } = useSession(); - const userId = session?.user?.email; + const { data: session } = useSession() + const userId = session?.user?.email const { data: sites } = useSWR( userId && `/api/site?userId=${userId}`, fetcher - ); + ) async function createSite(e) { - const res = await fetch("/api/site", { - method: "POST", + const res = await fetch('/api/site', { + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify({ userId: userId, @@ -57,10 +57,10 @@ export default function AppIndex() { subdomain: e.target.subdomain.value, description: e.target.description.value, }), - }); + }) if (res.ok) { - const data = await res.json(); - router.push(`/site/${data.siteId}`); + const data = await res.json() + router.push(`/site/${data.siteId}`) } } @@ -69,9 +69,9 @@ export default function AppIndex() {
    { - event.preventDefault(); - setCreatingSite(true); - createSite(event); + event.preventDefault() + setCreatingSite(true) + createSite(event) }} className="inline-block w-full max-w-md pt-8 overflow-hidden text-center align-middle transition-all bg-white shadow-xl rounded-lg" > @@ -121,8 +121,8 @@ export default function AppIndex() { type="button" className="w-full px-5 py-5 text-sm text-gray-600 hover:text-black border-t border-gray-300 rounded-bl focus:outline-none focus:ring-0 transition-all ease-in-out duration-150" onClick={() => { - setError(null); - setShowModal(false); + setError(null) + setShowModal(false) }} > CANCEL @@ -133,11 +133,11 @@ export default function AppIndex() { disabled={creatingSite || error} className={`${ creatingSite || error - ? "cursor-not-allowed text-gray-400 bg-gray-50" - : "bg-white text-gray-600 hover:text-black" + ? 'cursor-not-allowed text-gray-400 bg-gray-50' + : 'bg-white text-gray-600 hover:text-black' } w-full px-5 py-5 text-sm border-t border-l border-gray-300 rounded-br focus:outline-none focus:ring-0 transition-all ease-in-out duration-150`} > - {creatingSite ? : "CREATE SITE"} + {creatingSite ? : 'CREATE SITE'}
    @@ -223,5 +223,5 @@ export default function AppIndex() {
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/pages/app/login.js b/solutions/platforms-slate-supabase/pages/app/login.js index 8005a7c4a9..212c720a53 100644 --- a/solutions/platforms-slate-supabase/pages/app/login.js +++ b/solutions/platforms-slate-supabase/pages/app/login.js @@ -1,15 +1,15 @@ -import { signIn } from "next-auth/react"; -import Head from "next/head"; -import { useState } from "react"; -import LoadingDots from "@/components/app/loading-dots"; +import { signIn } from 'next-auth/react' +import Head from 'next/head' +import { useState } from 'react' +import LoadingDots from '@/components/app/loading-dots' -const pageTitle = "Login"; -const logo = "/favicon.ico"; +const pageTitle = 'Login' +const logo = '/favicon.ico' const description = - "Platforms Starter Kit is a comprehensive template for building multi-tenant applications with custom domains."; + 'Platforms Starter Kit is a comprehensive template for building multi-tenant applications with custom domains.' export default function Login() { - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(false) return (
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/pages/app/post/[id]/index.js b/solutions/platforms-slate-supabase/pages/app/post/[id]/index.js index 17e6759f42..9aaa63ffe7 100644 --- a/solutions/platforms-slate-supabase/pages/app/post/[id]/index.js +++ b/solutions/platforms-slate-supabase/pages/app/post/[id]/index.js @@ -1,87 +1,87 @@ -import Layout from "@/components/app/Layout"; -import useSWR from "swr"; -import { useDebounce } from "use-debounce"; -import { useState, useEffect, useCallback, useMemo } from "react"; -import { Editable, withReact, useSlate, Slate } from "slate-react"; -import { Editor, createEditor } from "slate"; -import { withHistory } from "slate-history"; -import TextareaAutosize from "react-textarea-autosize"; -import { useRouter } from "next/router"; -import isHotkey from "is-hotkey"; -import LoadingDots from "@/components/app/loading-dots"; -import Loader from "@/components/app/Loader"; -import Leaf from "@/components/editor/Leaf"; -import Element from "@/components/editor/Element"; +import Layout from '@/components/app/Layout' +import useSWR from 'swr' +import { useDebounce } from 'use-debounce' +import { useState, useEffect, useCallback, useMemo } from 'react' +import { Editable, withReact, useSlate, Slate } from 'slate-react' +import { Editor, createEditor } from 'slate' +import { withHistory } from 'slate-history' +import TextareaAutosize from 'react-textarea-autosize' +import { useRouter } from 'next/router' +import isHotkey from 'is-hotkey' +import LoadingDots from '@/components/app/loading-dots' +import Loader from '@/components/app/Loader' +import Leaf from '@/components/editor/Leaf' +import Element from '@/components/editor/Element' -const fetcher = (...args) => fetch(...args).then((res) => res.json()); +const fetcher = (...args) => fetch(...args).then((res) => res.json()) const HOTKEYS = { - "cmd+b": "bold", - "cmd+i": "italic", - "cmd+u": "underline", - "cmd+c": "code", -}; + 'cmd+b': 'bold', + 'cmd+i': 'italic', + 'cmd+u': 'underline', + 'cmd+c': 'code', +} const formatSavedTime = (time) => { - const date = new Date(time); - const month = Intl.DateTimeFormat("en", { month: "short" }).format(date); - const day = Intl.DateTimeFormat("en", { day: "2-digit" }).format(date); - const mins = Intl.DateTimeFormat("en", { - hour: "numeric", - minute: "numeric", - }).format(date); - return `Last saved at ${month} ${day} ${mins}`; -}; + const date = new Date(time) + const month = Intl.DateTimeFormat('en', { month: 'short' }).format(date) + const day = Intl.DateTimeFormat('en', { day: '2-digit' }).format(date) + const mins = Intl.DateTimeFormat('en', { + hour: 'numeric', + minute: 'numeric', + }).format(date) + return `Last saved at ${month} ${day} ${mins}` +} const isMarkActive = (editor, format) => { - return !!Editor.marks(editor) ? Editor.marks(editor)[format] : false; -}; + return !!Editor.marks(editor) ? Editor.marks(editor)[format] : false +} const Button = ({ active, ...rest }) => { return ( - ); -}; + ) +} const ToolbarButton = ({ format, icon, setCurrentMark, toggleMark }) => { - const editor = useSlate(); + const editor = useSlate() useEffect(() => { if (isMarkActive(editor, format)) { - setCurrentMark(format); + setCurrentMark(format) } - }, [editor, format]); + }, [editor, format]) return ( - ); -}; + ) +} export default function Post() { - const router = useRouter(); - const { id: postId } = router.query; - const renderElement = useCallback((props) => , []); - const renderLeaf = useCallback((props) => , []); + const router = useRouter() + const { id: postId } = router.query + const renderElement = useCallback((props) => , []) + const renderLeaf = useCallback((props) => , []) - const editor = useMemo(() => withHistory(withReact(createEditor())), []); + const editor = useMemo(() => withHistory(withReact(createEditor())), []) - const [currentMark, setCurrentMark] = useState(null); - const [publishing, setPublishing] = useState(false); - const [disabled, setDisabled] = useState(true); - const [savedState, setSavedState] = useState("Saving post"); - const [postData, setPostData] = useState(); // The created post. - const [debouncedData] = useDebounce(postData, 1000); + const [currentMark, setCurrentMark] = useState(null) + const [publishing, setPublishing] = useState(false) + const [disabled, setDisabled] = useState(true) + const [savedState, setSavedState] = useState('Saving post') + const [postData, setPostData] = useState() // The created post. + const [debouncedData] = useDebounce(postData, 1000) const { data: post, isValidating } = useSWR( `/api/post?postId=${postId}`, @@ -89,10 +89,10 @@ export default function Post() { { revalidateOnFocus: false, onError: () => { - router.push("/"); + router.push('/') }, } - ); + ) useEffect(() => { if (post) { @@ -100,16 +100,16 @@ export default function Post() { title: post.title, description: post.description, content: post.content, - }); - setSavedState(formatSavedTime(post.updatedAt)); + }) + setSavedState(formatSavedTime(post.updatedAt)) } - }, [post]); + }, [post]) useEffect(() => { if (debouncedData?.title) { - saveChanges(debouncedData); + saveChanges(debouncedData) } - }, [debouncedData]); + }, [debouncedData]) useEffect(() => { if ( @@ -118,31 +118,31 @@ export default function Post() { postData?.content && !publishing ) - setDisabled(false); - else setDisabled(true); - }, [publishing, postData]); + setDisabled(false) + else setDisabled(true) + }, [publishing, postData]) useEffect(() => { const clickedSave = (e) => { - let charCode = String.fromCharCode(e.which).toLowerCase(); - if ((e.ctrlKey || e.metaKey) && charCode === "s") { - e.preventDefault(); - saveChanges(postData); + let charCode = String.fromCharCode(e.which).toLowerCase() + if ((e.ctrlKey || e.metaKey) && charCode === 's') { + e.preventDefault() + saveChanges(postData) } - }; - window.addEventListener("keydown", clickedSave); + } + window.addEventListener('keydown', clickedSave) return () => { - window.removeEventListener("keydown", clickedSave); - }; - }, [postData]); + window.removeEventListener('keydown', clickedSave) + } + }, [postData]) const saveChanges = async (data) => { - setSavedState("Saving changes..."); + setSavedState('Saving changes...') - const response = await fetch("/api/post", { - method: "PUT", + const response = await fetch('/api/post', { + method: 'PUT', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify({ id: postId, @@ -150,34 +150,34 @@ export default function Post() { description: data.description, content: data.content, }), - }); + }) if (response.ok) { - const responseData = await response.json(); + const responseData = await response.json() - setSavedState(formatSavedTime(responseData.updatedAt)); + setSavedState(formatSavedTime(responseData.updatedAt)) } else { - setSavedState("Failed to save."); + setSavedState('Failed to save.') } - }; + } const toggleMark = (editor, format) => { - const isActive = isMarkActive(editor, format); + const isActive = isMarkActive(editor, format) if (isActive) { - Editor.removeMark(editor, format); + Editor.removeMark(editor, format) } else { - Editor.addMark(editor, format, true); + Editor.addMark(editor, format, true) } - }; + } const publish = async () => { - setPublishing(true); + setPublishing(true) // R: This should be a @lib and a one liner. const response = await fetch(`/api/post`, { - method: "PUT", + method: 'PUT', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify({ id: postId, @@ -186,18 +186,18 @@ export default function Post() { content: postData.content, published: true, }), - }); - await response.json(); + }) + await response.json() // R: NEXT_PUBLIC_for reusability - router.push(`https://${post.site.subdomain}.vercel.im/${post.slug}`); - }; + router.push(`https://${post.site.subdomain}.vercel.im/${post.slug}`) + } if (isValidating && !post?.site.id) { return ( - ); + ) } return ( @@ -285,10 +285,10 @@ export default function Post() { onKeyDown={(event) => { for (const hotkey in HOTKEYS) { if (isHotkey(hotkey, event)) { - event.preventDefault(); - const mark = HOTKEYS[hotkey]; - toggleMark(editor, mark); - setCurrentMark(mark); + event.preventDefault() + const mark = HOTKEYS[hotkey] + toggleMark(editor, mark) + setCurrentMark(mark) } } }} @@ -300,31 +300,31 @@ export default function Post() {
    -

    {post?.imlished ? "Published" : "Draft"}

    +

    {post?.imlished ? 'Published' : 'Draft'}

    {savedState}

    - ); + ) } diff --git a/solutions/platforms-slate-supabase/pages/app/post/[id]/settings.js b/solutions/platforms-slate-supabase/pages/app/post/[id]/settings.js index 78595c517e..d27d5c4e3e 100644 --- a/solutions/platforms-slate-supabase/pages/app/post/[id]/settings.js +++ b/solutions/platforms-slate-supabase/pages/app/post/[id]/settings.js @@ -1,21 +1,21 @@ -import Layout from "@/components/app/Layout"; -import useSWR from "swr"; -import BlurImage from "@/components/BlurImage"; -import CloudinaryUploadWidget from "@/components/Cloudinary"; -import LoadingDots from "@/components/app/loading-dots"; -import saveImage from "@/lib/save-image"; -import Modal from "@/components/Modal"; -import { useState, useEffect } from "react"; -import { useRouter } from "next/router"; -import Loader from "@/components/app/Loader"; -import toast, { Toaster } from "react-hot-toast"; +import Layout from '@/components/app/Layout' +import useSWR from 'swr' +import BlurImage from '@/components/BlurImage' +import CloudinaryUploadWidget from '@/components/Cloudinary' +import LoadingDots from '@/components/app/loading-dots' +import saveImage from '@/lib/save-image' +import Modal from '@/components/Modal' +import { useState, useEffect } from 'react' +import { useRouter } from 'next/router' +import Loader from '@/components/app/Loader' +import toast, { Toaster } from 'react-hot-toast' -const fetcher = (...args) => fetch(...args).then((res) => res.json()); +const fetcher = (...args) => fetch(...args).then((res) => res.json()) export default function PostSettings() { - const router = useRouter(); - const { id } = router.query; - const postId = id; + const router = useRouter() + const { id } = router.query + const postId = id const { data: settings, isValidating } = useSWR( `/api/post?postId=${postId}`, @@ -23,19 +23,19 @@ export default function PostSettings() { { revalidateOnFocus: false, onError: () => { - router.push("/"); + router.push('/') }, } - ); + ) - const [saving, setSaving] = useState(false); - const [showDeleteModal, setShowDeleteModal] = useState(false); - const [deletingPost, setDeletingPost] = useState(false); + const [saving, setSaving] = useState(false) + const [showDeleteModal, setShowDeleteModal] = useState(false) + const [deletingPost, setDeletingPost] = useState(false) const [data, setData] = useState({ image: settings?.image, imageBlurhash: settings?.imageBlurhash, - }); + }) useEffect(() => { if (settings) @@ -43,15 +43,15 @@ export default function PostSettings() { slug: settings.slug, image: settings.image, imageBlurhash: settings.imageBlurhash, - }); - }, [settings]); + }) + }, [settings]) async function savePostSettings(data) { - setSaving(true); - const response = await fetch("/api/post", { - method: "PUT", + setSaving(true) + const response = await fetch('/api/post', { + method: 'PUT', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, body: JSON.stringify({ id: postId, @@ -59,20 +59,20 @@ export default function PostSettings() { image: data.image, imageBlurhash: data.imageBlurhash, }), - }); + }) if (response.ok) { - setSaving(false); - toast.success(`Changes Saved`); + setSaving(false) + toast.success(`Changes Saved`) } } async function deletePost(postId) { - setDeletingPost(true); + setDeletingPost(true) const response = await fetch(`/api/post?postId=${postId}`, { - method: "DELETE", - }); + method: 'DELETE', + }) if (response.ok) { - router.push(`/site/${settings.site.id}`); + router.push(`/site/${settings.site.id}`) } } @@ -81,7 +81,7 @@ export default function PostSettings() { - ); + ) return ( <> @@ -117,7 +117,7 @@ export default function PostSettings() {

    Thumbnail Image

    @@ -218,20 +218,20 @@ export default function PostSettings() {
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/pages/app/site/[id]/drafts.js b/solutions/platforms-slate-supabase/pages/app/site/[id]/drafts.js index 78a52150db..91357cb473 100644 --- a/solutions/platforms-slate-supabase/pages/app/site/[id]/drafts.js +++ b/solutions/platforms-slate-supabase/pages/app/site/[id]/drafts.js @@ -1,20 +1,20 @@ -import { useState } from "react"; -import Layout from "@/components/app/Layout"; -import BlurImage from "@/components/BlurImage"; -import LoadingDots from "@/components/app/loading-dots"; -import Link from "next/link"; -import Image from "next/image"; -import { useRouter } from "next/router"; -import useSWR from "swr"; +import { useState } from 'react' +import Layout from '@/components/app/Layout' +import BlurImage from '@/components/BlurImage' +import LoadingDots from '@/components/app/loading-dots' +import Link from 'next/link' +import Image from 'next/image' +import { useRouter } from 'next/router' +import useSWR from 'swr' -const fetcher = (...args) => fetch(...args).then((res) => res.json()); +const fetcher = (...args) => fetch(...args).then((res) => res.json()) export default function SiteDrafts() { - const [creatingPost, setCreatingPost] = useState(false); + const [creatingPost, setCreatingPost] = useState(false) - const router = useRouter(); - const { id } = router.query; - const siteId = id; + const router = useRouter() + const { id } = router.query + const siteId = id const { data } = useSWR( siteId && `/api/get-posts?siteId=${siteId}&published=false`, @@ -22,22 +22,22 @@ export default function SiteDrafts() { { onSuccess: (data) => { if (!data?.site) { - router.push("/"); + router.push('/') } }, } - ); + ) async function createPost(siteId) { const res = await fetch(`/api/create-post?siteId=${siteId}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, - }); + }) if (res.ok) { - const data = await res.json(); - router.push(`/post/${data.postId}`); + const data = await res.json() + router.push(`/post/${data.postId}`) } } @@ -46,18 +46,18 @@ export default function SiteDrafts() {

    - {" "} - Drafts for {data ? data?.site?.name : "..."} + {' '} + Drafts for {data ? data?.site?.name : '...'}

    - {post.title || "Untitled Post"} + {post.title || 'Untitled Post'}

    {post.description || - "No description provided. Click to edit."} + 'No description provided. Click to edit.'}

    - ); + ) } diff --git a/solutions/platforms-slate-supabase/pages/app/site/[id]/index.js b/solutions/platforms-slate-supabase/pages/app/site/[id]/index.js index ee724131cd..f4dbaead21 100644 --- a/solutions/platforms-slate-supabase/pages/app/site/[id]/index.js +++ b/solutions/platforms-slate-supabase/pages/app/site/[id]/index.js @@ -1,19 +1,19 @@ -import { useState } from "react"; -import Layout from "@/components/app/Layout"; -import BlurImage from "@/components/BlurImage"; -import LoadingDots from "@/components/app/loading-dots"; -import Link from "next/link"; -import { useRouter } from "next/router"; -import useSWR from "swr"; +import { useState } from 'react' +import Layout from '@/components/app/Layout' +import BlurImage from '@/components/BlurImage' +import LoadingDots from '@/components/app/loading-dots' +import Link from 'next/link' +import { useRouter } from 'next/router' +import useSWR from 'swr' -const fetcher = (...args) => fetch(...args).then((res) => res.json()); +const fetcher = (...args) => fetch(...args).then((res) => res.json()) export default function SiteIndex() { - const [creatingPost, setCreatingPost] = useState(false); + const [creatingPost, setCreatingPost] = useState(false) - const router = useRouter(); - const { id } = router.query; - const siteId = id; + const router = useRouter() + const { id } = router.query + const siteId = id const { data } = useSWR( siteId && `/api/post?siteId=${siteId}&published=true`, @@ -21,22 +21,22 @@ export default function SiteIndex() { { onSuccess: (data) => { if (!data?.site) { - router.push("/"); + router.push('/') } }, } - ); + ) async function createPost(siteId) { const res = await fetch(`/api/post?siteId=${siteId}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', }, - }); + }) if (res.ok) { - const data = await res.json(); - router.push(`/post/${data.postId}`); + const data = await res.json() + router.push(`/post/${data.postId}`) } } @@ -45,17 +45,17 @@ export default function SiteIndex() {

    - Posts for {data ? data?.site?.name : "..."} + Posts for {data ? data?.site?.name : '...'}

    - ); + ) } - \ No newline at end of file diff --git a/solutions/platforms-slate-supabase/pages/app/site/[id]/settings.js b/solutions/platforms-slate-supabase/pages/app/site/[id]/settings.js index 2c0057031f..1097a557ac 100644 --- a/solutions/platforms-slate-supabase/pages/app/site/[id]/settings.js +++ b/solutions/platforms-slate-supabase/pages/app/site/[id]/settings.js @@ -1,37 +1,37 @@ -import Layout from "@/components/app/Layout"; -import toast, { Toaster } from "react-hot-toast"; -import BlurImage from "@/components/BlurImage"; -import CloudinaryUploadWidget from "@/components/Cloudinary"; -import LoadingDots from "@/components/app/loading-dots"; -import saveImage from "@/lib/save-image"; +import Layout from '@/components/app/Layout' +import toast, { Toaster } from 'react-hot-toast' +import BlurImage from '@/components/BlurImage' +import CloudinaryUploadWidget from '@/components/Cloudinary' +import LoadingDots from '@/components/app/loading-dots' +import saveImage from '@/lib/save-image' -import { useState, useEffect } from "react"; -import { useSession } from "next-auth/react"; +import { useState, useEffect } from 'react' +import { useSession } from 'next-auth/react' export default function AppSettings() { - const { data: session } = useSession(); - const [saving, setSaving] = useState(false); + const { data: session } = useSession() + const [saving, setSaving] = useState(false) - const [data, setData] = useState(null); + const [data, setData] = useState(null) useEffect(() => { if (session) setData({ ...session.user, - }); - }, [session]); + }) + }, [session]) async function saveSettings(data) { - setSaving(true); - const response = await fetch("/api/save-settings", { - method: "POST", + setSaving(true) + const response = await fetch('/api/save-settings', { + method: 'POST', body: JSON.stringify({ ...data, }), - }); + }) if (response.ok) { - setSaving(false); - toast.success(`Changes Saved`); + setSaving(false) + toast.success(`Changes Saved`) } } @@ -81,7 +81,7 @@ export default function AppSettings() {

    Display Picture

    - ); + ) } diff --git a/solutions/platforms-slate-supabase/pages/home/index.js b/solutions/platforms-slate-supabase/pages/home/index.js index 9d063e90c3..670da73de4 100644 --- a/solutions/platforms-slate-supabase/pages/home/index.js +++ b/solutions/platforms-slate-supabase/pages/home/index.js @@ -1,5 +1,5 @@ -import Head from "next/head"; -import Image from "next/image"; +import Head from 'next/head' +import Image from 'next/image' export default function Home() { return ( @@ -18,5 +18,5 @@ export default function Home() { />
    - ); + ) } diff --git a/solutions/platforms-slate-supabase/postcss.config.js b/solutions/platforms-slate-supabase/postcss.config.js index 3687d286ec..3fa0a9514d 100644 --- a/solutions/platforms-slate-supabase/postcss.config.js +++ b/solutions/platforms-slate-supabase/postcss.config.js @@ -5,4 +5,4 @@ module.exports = { tailwindcss: {}, autoprefixer: {}, }, -}; +} diff --git a/solutions/platforms-slate-supabase/styles/globals.css b/solutions/platforms-slate-supabase/styles/globals.css index 64fbed6862..43624b48a3 100644 --- a/solutions/platforms-slate-supabase/styles/globals.css +++ b/solutions/platforms-slate-supabase/styles/globals.css @@ -1,4 +1,4 @@ -@import url("/fonts/stylesheet.css"); +@import url('/fonts/stylesheet.css'); @tailwind base; @tailwind components; diff --git a/solutions/platforms-slate-supabase/tailwind.config.js b/solutions/platforms-slate-supabase/tailwind.config.js index 093822b06c..77ba1debc9 100644 --- a/solutions/platforms-slate-supabase/tailwind.config.js +++ b/solutions/platforms-slate-supabase/tailwind.config.js @@ -1,72 +1,72 @@ -const defaultTheme = require("tailwindcss/defaultTheme"); +const defaultTheme = require('tailwindcss/defaultTheme') module.exports = { mode: 'jit', content: [ - "./pages/**/*.{js,ts,jsx,tsx}", - "./components/**/*.{js,ts,jsx,tsx}", - "./lib/**/*.{js,ts,jsx,tsx}", + './pages/**/*.{js,ts,jsx,tsx}', + './components/**/*.{js,ts,jsx,tsx}', + './lib/**/*.{js,ts,jsx,tsx}', ], darkMode: 'media', theme: { fontFamily: { - cal: ["Cal Sans", "Inter var", "sans-serif"], + cal: ['Cal Sans', 'Inter var', 'sans-serif'], }, extend: { colors: { current: 'currentColor', }, width: { - 1536: "1536px", + 1536: '1536px', }, height: { - 150: "37.5rem", + 150: '37.5rem', }, margin: { - 30: "7.5rem", + 30: '7.5rem', }, fontFamily: { - sans: ["Inter var", ...defaultTheme.fontFamily.sans], - mono: ["Consolas", ...defaultTheme.fontFamily.mono], + sans: ['Inter var', ...defaultTheme.fontFamily.sans], + mono: ['Consolas', ...defaultTheme.fontFamily.mono], }, typography: { DEFAULT: { css: { h1: { - fontFamily: "Cal Sans", + fontFamily: 'Cal Sans', }, h2: { - fontFamily: "Cal Sans", + fontFamily: 'Cal Sans', }, h3: { - fontFamily: "Cal Sans", + fontFamily: 'Cal Sans', }, - "blockquote p:first-of-type::before": { content: "none" }, - "blockquote p:first-of-type::after": { content: "none" }, + 'blockquote p:first-of-type::before': { content: 'none' }, + 'blockquote p:first-of-type::after': { content: 'none' }, }, }, }, keyframes: { wiggle: { - "0%, 100%": { - transform: "translateX(0%)", - transformOrigin: "50% 50%", + '0%, 100%': { + transform: 'translateX(0%)', + transformOrigin: '50% 50%', }, - "15%": { transform: "translateX(-6px) rotate(-6deg)" }, - "30%": { transform: "translateX(9px) rotate(6deg)" }, - "45%": { transform: "translateX(-9px) rotate(-3.6deg)" }, - "60%": { transform: "translateX(3px) rotate(2.4deg)" }, - "75%": { transform: "translateX(-2px) rotate(-1.2deg)" }, + '15%': { transform: 'translateX(-6px) rotate(-6deg)' }, + '30%': { transform: 'translateX(9px) rotate(6deg)' }, + '45%': { transform: 'translateX(-9px) rotate(-3.6deg)' }, + '60%': { transform: 'translateX(3px) rotate(2.4deg)' }, + '75%': { transform: 'translateX(-2px) rotate(-1.2deg)' }, }, }, animation: { - wiggle: "wiggle 0.8s both", + wiggle: 'wiggle 0.8s both', }, }, }, plugins: [ - require("@tailwindcss/typography"), - require("@tailwindcss/forms"), - require("@tailwindcss/line-clamp"), + require('@tailwindcss/typography'), + require('@tailwindcss/forms'), + require('@tailwindcss/line-clamp'), ], -}; +} diff --git a/solutions/reduce-image-bandwidth-usage/README.md b/solutions/reduce-image-bandwidth-usage/README.md index d291f29fd9..bb6933ba74 100644 --- a/solutions/reduce-image-bandwidth-usage/README.md +++ b/solutions/reduce-image-bandwidth-usage/README.md @@ -7,6 +7,7 @@ This example shows how to reduce bandwidth and processing costs when using diffe Using [`layout=fill`](https://nextjs.org/docs/api-reference/next/image#layout) in `next/image` is one of the most common patterns as it let us use responsive parents and (along with the [`objectFit`](https://nextjs.org/docs/api-reference/next/image#objectfit) prop) our images will resize to it perfectly. But this leads to a common problem; as we don't know how large our parent might be, we can't serve an optimized image. Our card is represented by this code: + ```tsx @@ -16,9 +17,11 @@ Our card is represented by this code: But wait, given this code we end up with this 👇 ![01](./public/docs/screenshot-1.jpg) + > Our element has a width of 256px but we are serving a 1000px image! The [`sizes`](https://nextjs.org/docs/api-reference/next/image#sizes) prop provides information about how wide the image will be at different breakpoints when using `layout="responsive"` or `layout="fill"`. In this case our card limits the width of the card to a maximum of `256px`. So if we update our code to use sizes like this: + ```tsx @@ -26,6 +29,7 @@ The [`sizes`](https://nextjs.org/docs/api-reference/next/image#sizes) prop provi ``` ![02](./public/docs/screenshot-2.jpg) + > Now we are being served with an optimized image. We also have a lot of images available for different viewport sizes that will be generated (and cached) on demand just when needed. By default, a variant will be available for every [`device size`](https://nextjs.org/docs/api-reference/next/image#device-sizes) configured. But we can also specify [`image sizes`](https://nextjs.org/docs/api-reference/next/image#image-sizes) that will be concatenated to the variants generated by device sizes when using `layout="responsive"` or `layout="fill"`. @@ -33,11 +37,13 @@ We also have a lot of images available for different viewport sizes that will be ## How to load optimized images using layout="fixed" or layout="intrinsic" This layouts force us to define a width and height of the image so its easier to determine the size of the variants that has to be generated so we don't have to define any extra properties to get an optimized image. So, given this code: + ```tsx ``` + > "intrinsic" is the default layout > We get back a correct optimized image diff --git a/solutions/reduce-image-bandwidth-usage/components/Card.tsx b/solutions/reduce-image-bandwidth-usage/components/Card.tsx index 418d714fa2..d659fcc289 100644 --- a/solutions/reduce-image-bandwidth-usage/components/Card.tsx +++ b/solutions/reduce-image-bandwidth-usage/components/Card.tsx @@ -1,15 +1,15 @@ -import React from "react"; +import React from 'react' interface Props { - children: React.ReactElement; + children: React.ReactElement } -const Card: React.VFC = ({children}: Props) => { +const Card: React.VFC = ({ children }: Props) => { return (
    {children}
    - ); + ) } -export default Card; +export default Card diff --git a/solutions/reduce-image-bandwidth-usage/components/Snippet.tsx b/solutions/reduce-image-bandwidth-usage/components/Snippet.tsx index 02241a79de..0a22d2e4bb 100644 --- a/solutions/reduce-image-bandwidth-usage/components/Snippet.tsx +++ b/solutions/reduce-image-bandwidth-usage/components/Snippet.tsx @@ -1,15 +1,15 @@ -import React from "react"; +import React from 'react' interface Props { - children: string; + children: string } -const Snippet:React.VFC = ({children}) => { +const Snippet: React.VFC = ({ children }) => { return (
           {children}
         
    - ); + ) } -export default Snippet; +export default Snippet diff --git a/solutions/reduce-image-bandwidth-usage/pages/index.tsx b/solutions/reduce-image-bandwidth-usage/pages/index.tsx index a42bc837b8..adde884619 100644 --- a/solutions/reduce-image-bandwidth-usage/pages/index.tsx +++ b/solutions/reduce-image-bandwidth-usage/pages/index.tsx @@ -1,18 +1,18 @@ import Head from 'next/head' -import Image from "next/image"; -import { Layout, Text, Page, Code, Link } from '@vercel/examples-ui'; +import Image from 'next/image' +import { Layout, Text, Page, Code, Link } from '@vercel/examples-ui' -import Card from "../components/Card" -import Snippet from '../components/Snippet'; +import Card from '../components/Card' +import Snippet from '../components/Snippet' -import screenshot1 from "../public/docs/screenshot-1.jpg" -import screenshot2 from "../public/docs/screenshot-2.jpg" -import screenshot3 from "../public/docs/screenshot-3.jpg" +import screenshot1 from '../public/docs/screenshot-1.jpg' +import screenshot2 from '../public/docs/screenshot-2.jpg' +import screenshot3 from '../public/docs/screenshot-3.jpg' const CARD = { - "id": "617a8bb9637d9400182bd6fe", - "title": "Next.js image example", - "thumbnail": "/logo.jpg", + id: '617a8bb9637d9400182bd6fe', + title: 'Next.js image example', + thumbnail: '/logo.jpg', } function Home() { @@ -24,8 +24,13 @@ function Home() { - Reduce next/image bandwidth usage - This example shows how to reduce bandwidth and processing costs when using different layouts. + + Reduce next/image bandwidth usage + + + This example shows how to reduce bandwidth and processing costs when + using different layouts. +
    @@ -33,7 +38,18 @@ function Home() { Using layout="fill" or layout="responsive" - Using layout=fill in next/image is one of the most common patterns as it let us use responsive parents and (along with the objectFit prop) our images will resize to it perfectly. But this leads to a common problem; as we don't know how large our parent might be, we can't serve an optimized image. + Using{' '} + + layout=fill + {' '} + in next/image is one of the most common patterns as it let + us use responsive parents and (along with the{' '} + + objectFit + {' '} + prop) our images will resize to it perfectly. But this leads to a common + problem; as we don't know how large our parent might be, we can't serve + an optimized image.
    @@ -45,13 +61,29 @@ function Home() { `} - But wait, given this code we end up with this 👇. Our element has a width of 256px but we are serving a 1000px image! + + But wait, given this code we end up with this 👇. Our element has a + width of 256px but we are serving a 1000px image! + - The sizes prop provides information about how wide the image will be at different breakpoints when using layout="responsive" or layout="fill". In this case our card limits the width of the image to a maximum of 256px. So if we update our code to use sizes like this: + The{' '} + + sizes + {' '} + prop provides information about how wide the image will be at + different breakpoints when using layout="responsive" or{' '} + layout="fill". In this case our card limits the width of + the image to a maximum of 256px. So if we update our code + to use sizes like this: - {CARD.title} + {CARD.title} {` @@ -59,11 +91,21 @@ function Home() { `} + Now we are being served with an optimized image. - Now we are being served with an optimized image. - - - We also have a lot of images available for different viewport sizes that will be generated (and cached) on demand just when needed. By default, a variant will be available for every device size configured. But we can also specify image sizes that will be concatenated to the variants generated by device sizes when using layout="responsive" or layout="fill". + We also have a lot of images available for different viewport sizes + that will be generated (and cached) on demand just when needed. By + default, a variant will be available for every{' '} + + device size + {' '} + configured. But we can also specify{' '} + + image sizes + {' '} + that will be concatenated to the variants generated by device sizes + when using layout="responsive" or{' '} + layout="fill".
    @@ -73,11 +115,18 @@ function Home() { Using layout="fixed" or layout="intrinsic" - This layouts force us to define a width and height of the image so its easier to determine the size of the variants that has to be generated so we don't have to define any extra properties to get an optimized image. + This layouts force us to define a width and height of the image so its + easier to determine the size of the variants that has to be generated so + we don't have to define any extra properties to get an optimized image.
    - {CARD.title} + {CARD.title} {` @@ -85,7 +134,10 @@ function Home() { `} - intrinsic is the default layout so we don't have to define it. We get back a correct optimized image. + + intrinsic is the default layout so we don't have to + define it. We get back a correct optimized image. +
    ) diff --git a/solutions/reuse-responses/api.ts b/solutions/reuse-responses/api.ts index b276727615..abd14cb1ad 100644 --- a/solutions/reuse-responses/api.ts +++ b/solutions/reuse-responses/api.ts @@ -1,37 +1,43 @@ -import {promises as fs} from "fs" +import { promises as fs } from 'fs' import path from 'path' -import { Product } from "./types" +import { Product } from './types' -const PRODUCTS: Product[] = [{ - id: 'mug', - title: 'Vercel Mug', - description: 'Limited edition', - price: 15 -}, { - id: 'hoodie', - title: 'Vercel Hoodie', - description: 'Limited edition', - price: 35 -}] +const PRODUCTS: Product[] = [ + { + id: 'mug', + title: 'Vercel Mug', + description: 'Limited edition', + price: 15, + }, + { + id: 'hoodie', + title: 'Vercel Hoodie', + description: 'Limited edition', + price: 35, + }, +] const api = { list: async () => { return PRODUCTS }, fetch: async (id: Product['id']) => { - return PRODUCTS.find(product => product.id === id) + return PRODUCTS.find((product) => product.id === id) }, cache: { get: async (id: string): Promise => { const data = await fs.readFile(path.join(process.cwd(), 'products.db')) const products: Product[] = JSON.parse(data as unknown as string) - return products.find(product => product.id === id) + return products.find((product) => product.id === id) }, set: async (products: Product[]) => { - return fs.writeFile(path.join(process.cwd(), 'products.db'), JSON.stringify(products)) - } - } + return fs.writeFile( + path.join(process.cwd(), 'products.db'), + JSON.stringify(products) + ) + }, + }, } export default api diff --git a/solutions/reuse-responses/components/ProductCard.tsx b/solutions/reuse-responses/components/ProductCard.tsx index 4010f88bc8..4ec2cde9ff 100644 --- a/solutions/reuse-responses/components/ProductCard.tsx +++ b/solutions/reuse-responses/components/ProductCard.tsx @@ -1,10 +1,10 @@ -import type { Product } from "../types" +import type { Product } from '../types' interface Props { - product: Product; + product: Product } -export default function ProductCard({product}: Props) { +export default function ProductCard({ product }: Props) { return (
    @@ -19,5 +19,5 @@ export default function ProductCard({product}: Props) {
    - ); -} \ No newline at end of file + ) +} diff --git a/solutions/reuse-responses/pages/[id].tsx b/solutions/reuse-responses/pages/[id].tsx index 3f87846226..2163e73c9c 100644 --- a/solutions/reuse-responses/pages/[id].tsx +++ b/solutions/reuse-responses/pages/[id].tsx @@ -2,18 +2,18 @@ import type { ParsedUrlQuery } from 'querystring' import type { GetStaticPaths, GetStaticProps } from 'next' import type { Product } from '../types' -import { PHASE_PRODUCTION_BUILD } from 'next/constants'; +import { PHASE_PRODUCTION_BUILD } from 'next/constants' import { Layout, Page, Link } from '@vercel/examples-ui' import api from '../api' import ProductCard from '../components/ProductCard' interface Props { - product: Product; + product: Product } interface Query extends ParsedUrlQuery { - id: string; + id: string } export const getStaticPaths: GetStaticPaths = async () => { @@ -24,17 +24,19 @@ export const getStaticPaths: GetStaticPaths = async () => { } return { - paths: products.map(product => ({ + paths: products.map((product) => ({ params: { - id: product.id + id: product.id, }, })), - fallback: 'blocking' + fallback: 'blocking', } } -export const getStaticProps: GetStaticProps = async ({params}) => { - let product = await api.cache.get(params?.id as string); +export const getStaticProps: GetStaticProps = async ({ + params, +}) => { + let product = await api.cache.get(params?.id as string) if (!product) { product = await api.fetch(params?.id as string) @@ -42,18 +44,18 @@ export const getStaticProps: GetStaticProps = async ({params}) => if (!product) { return { - notFound: true + notFound: true, } } return { props: { product, - } + }, } } -function Home({product}: Props) { +function Home({ product }: Props) { return (
    diff --git a/solutions/reuse-responses/pages/_app.tsx b/solutions/reuse-responses/pages/_app.tsx index 3698f79a86..28f65c0b08 100644 --- a/solutions/reuse-responses/pages/_app.tsx +++ b/solutions/reuse-responses/pages/_app.tsx @@ -9,10 +9,7 @@ function App({ Component, pageProps }: AppProps) { const Layout = getLayout(Component) return ( - + ) diff --git a/solutions/reuse-responses/pages/index.tsx b/solutions/reuse-responses/pages/index.tsx index 80a8b49776..9caa70aacf 100644 --- a/solutions/reuse-responses/pages/index.tsx +++ b/solutions/reuse-responses/pages/index.tsx @@ -9,24 +9,24 @@ import { Layout, Text, Page, Code, Link, List } from '@vercel/examples-ui' import api from '../api' import ProductCard from '../components/ProductCard' -import notOptimizing from "../public/not-optimizing-board.jpg" -import pageOptimizing from "../public/page-optimizing-board.jpg" -import appOptimizing from "../public/cross-page-optimizing-board.jpg" +import notOptimizing from '../public/not-optimizing-board.jpg' +import pageOptimizing from '../public/page-optimizing-board.jpg' +import appOptimizing from '../public/cross-page-optimizing-board.jpg' interface Props { - products: Product[]; + products: Product[] } -const Snippet: FC = ({children}) => { +const Snippet: FC = ({ children }) => { return (
           {children}
         
    - ); + ) } export const getStaticProps: GetStaticProps = async () => { - const products = await api.list(); + const products = await api.list() if (process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD) { await api.cache.set(products) @@ -34,40 +34,79 @@ export const getStaticProps: GetStaticProps = async () => { return { props: { - products - } + products, + }, } } -function Home({products}: Props) { +function Home({ products }: Props) { return ( Reusing responses - +
    Reusing responses at build time - In some applications, like an e-commerce we have to query our database for list and fetch operations that returns the same data schema. But given that we usually have to call this methods inside getStaticProps and getStaticPaths we end up querying our services way more times than needed. - Imagine the following scenario. We have an e-commerce with 100 products and two routes that we statically generate at build time, an / route that list all the products and a /[id] route that shows the product details. We asume that we have an endpoint that returns all the products with the relevant data we need to pre-render our page. Every roundtrip to our service take 150ms and consumes 1kb of bandwidth per product. - Calling the /api/product endpoint in getStaticPaths and calling /api/product/[id] endpoint in getStaticProps for each product: + + In some applications, like an e-commerce we have to query our database + for list and fetch operations that returns + the same data schema. But given that we usually have to call this + methods inside getStaticProps and{' '} + getStaticPaths we end up querying our services way more + times than needed. + + + Imagine the following scenario. We have an e-commerce with 100 + products and two routes that we statically generate at build time, an{' '} + / route that list all the products and a{' '} + /[id] route that shows the product details. We asume that + we have an endpoint that returns all the products with the relevant + data we need to pre-render our page. Every roundtrip to our service + take 150ms and consumes 1kb of bandwidth per product. + + + Calling the /api/product endpoint in{' '} + getStaticPaths and calling /api/product/[id]{' '} + endpoint in getStaticProps for each product: + -
  • getStaticPaths: 100kb bandwidth, 150ms execution time, 1 call.
  • -
  • getStaticProps: 100kb bandwidth, 15000ms execution time, 100 calls.
  • - Total: 200kb bandwidth, 15150ms execution time, 101 calls. + getStaticPaths: 100kb + bandwidth, 150ms execution time, 1 call. +
  • +
  • + getStaticProps: 100kb + bandwidth, 15000ms execution time, 100 calls. +
  • +
  • + Total:{' '} + 200kb bandwidth, 15150ms execution time, 101 calls.
  • - But what if we could reuse the response from getStaticPaths in our getStaticProps calls? + + But what if we could reuse the response from{' '} + getStaticPaths in our getStaticProps calls? + -
  • getStaticPaths: 100kb bandwidth, 150ms execution time, 1 call.
  • -
  • getStaticProps: 0kb bandwidth, ~ 0ms execution time. 0 calls.
  • - Total: 100kb bandwidth, 150ms execution time, 1 call. + getStaticPaths: 100kb + bandwidth, 150ms execution time, 1 call. +
  • +
  • + getStaticProps: 0kb + bandwidth, ~ 0ms execution time. 0 calls. +
  • +
  • + Total:{' '} + 100kb bandwidth, 150ms execution time, 1 call.
  • And what if we can reuse that cache at aplication level? @@ -77,11 +116,12 @@ function Home({products}: Props) {
    - - A real-world example + A real-world example + + Lets start with some unoptimized code for our /[id] page. - Lets start with some unoptimized code for our /[id] page. - {`export const getStaticPaths = async () => { + + {`export const getStaticPaths = async () => { const products = await api.list() return { @@ -110,8 +150,15 @@ export const getStaticProps = async ({params}) => { } }`} - Lets add a cache using fs to share state at build time between getStaticPaths and getStaticProps. We will add a cache property to api with a get and a set method to interact with the cache. - {`import {promises as fs} from 'fs' + + Lets add a cache using fs to share state at build time + between getStaticPaths and getStaticProps. + We will add a cache property to api with a{' '} + get and a set method to interact with the + cache. + + + {`import {promises as fs} from 'fs' ... @@ -129,8 +176,12 @@ const api = { } }`} - And we will use this methods in getStaticPaths and getStaticProps: - {`export const getStaticPaths = async () => { + + And we will use this methods in getStaticPaths and{' '} + getStaticProps: + + + {`export const getStaticPaths = async () => { const products = await api.list() await api.cache.set(products) @@ -165,9 +216,19 @@ export const getStaticProps = async ({params}) => { } }`} - That way we ensure to use always information cache-first and if we don't find it, we fallback to calling the API. If you want to optimize this to be cross-page you can move the cache to other file and reuse it. - But there is something else we should take care of. Our current code might collide with our revalidation process in case we do ISR, so we want to ensure to only read from cache if we are at build time. - {`import { PHASE_PRODUCTION_BUILD } from 'next/constants'; + + That way we ensure to use always information cache-first and if we + don't find it, we fallback to calling the API. If you want to optimize + this to be cross-page you can move the cache to other file and reuse + it. + + + But there is something else we should take care of. Our current code + might collide with our revalidation process in case we do ISR, so we + want to ensure to only read from cache if we are at build time. + + + {`import { PHASE_PRODUCTION_BUILD } from 'next/constants'; ... export const getStaticPaths = async () => { @@ -207,15 +268,25 @@ export const getStaticProps = async ({params}) => { } }`} - Now we check if NEXT_PHASE is PHASE_PRODUCTION_BUILD so we know we only write to cache at build time. If you want to always cache build-time responses instead of manually caching at page level, you can move the usage of the cache methods to the level needed for your application. + + Now we check if NEXT_PHASE is{' '} + PHASE_PRODUCTION_BUILD so we know we only write to cache + at build time. If you want to always cache build-time responses + instead of manually caching at page level, you can move the usage of + the cache methods to the level needed for your application. +

    - This is a list to our products, each one will redirect to the /[id] route that was generated reusing responses from the cache at build time. + + This is a list to our products, each one will redirect to the{' '} + /[id] route that was generated reusing responses from the + cache at build time. +
    - {products.map(product => ( + {products.map((product) => ( diff --git a/solutions/reuse-responses/types.ts b/solutions/reuse-responses/types.ts index b3bda66971..9e74c02bf7 100644 --- a/solutions/reuse-responses/types.ts +++ b/solutions/reuse-responses/types.ts @@ -1,6 +1,6 @@ export interface Product { - id: string; - title: string; - description: string; - price: number; -} \ No newline at end of file + id: string + title: string + description: string + price: number +} diff --git a/solutions/script-component-strategies/components/Snippet.tsx b/solutions/script-component-strategies/components/Snippet.tsx index bbc3e50598..639b82e4a6 100644 --- a/solutions/script-component-strategies/components/Snippet.tsx +++ b/solutions/script-component-strategies/components/Snippet.tsx @@ -1,11 +1,11 @@ -import type {VFC, ReactChild} from "react"; +import type { VFC, ReactChild } from 'react' -const Snippet:VFC<{children: ReactChild}> = ({children}) => { +const Snippet: VFC<{ children: ReactChild }> = ({ children }) => { return (
           {children}
         
    - ); + ) } -export default Snippet; \ No newline at end of file +export default Snippet diff --git a/solutions/script-component-strategies/pages/fb.tsx b/solutions/script-component-strategies/pages/fb.tsx index d5560559ff..e57191a323 100644 --- a/solutions/script-component-strategies/pages/fb.tsx +++ b/solutions/script-component-strategies/pages/fb.tsx @@ -3,8 +3,8 @@ import Script from 'next/script' import { Code, Layout, List, Page, Text } from '@vercel/examples-ui' interface Log { - time: Date; - text: string; + time: Date + text: string } function FBLazyLoad() { @@ -35,11 +35,14 @@ function FBLazyLoad() {
    lazyOnload FB sdk - You can check window.FB on browser console + + You can check window.FB on browser console + {log.map(({ time, text }) => (
  • - {time.toISOString()}: {text} + {time.toISOString()}:{' '} + {text}
  • ))}
    @@ -49,6 +52,6 @@ function FBLazyLoad() { ) } -FBLazyLoad.Layout = Layout; +FBLazyLoad.Layout = Layout -export default FBLazyLoad; \ No newline at end of file +export default FBLazyLoad diff --git a/solutions/script-component-strategies/pages/index.tsx b/solutions/script-component-strategies/pages/index.tsx index 9d190ea6ce..9066a44876 100644 --- a/solutions/script-component-strategies/pages/index.tsx +++ b/solutions/script-component-strategies/pages/index.tsx @@ -1,64 +1,111 @@ import Head from 'next/head' -import { Layout, Text, Page, Code, Link, List } from '@vercel/examples-ui'; -import Snippet from '../components/Snippet'; +import { Layout, Text, Page, Code, Link, List } from '@vercel/examples-ui' +import Snippet from '../components/Snippet' function Home() { return ( next/script strategies - +
    next/script strategies - The Next.js Script component, next/script, is an extension of the HTML {`