Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

With redis typescript #1

Open
wants to merge 12 commits into
base: canary
Choose a base branch
from
2 changes: 1 addition & 1 deletion docs/advanced-features/custom-document.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Or add a `className` to the `body` tag:
## Caveats

- The `<Head />` component used in `_document` is not the same as [`next/head`](/docs/api-reference/next/head.md). The `<Head />` component used here should only be used for any `<head>` code that is common for all pages. For all other cases, such as `<title>` tags, we recommend using [`next/head`](/docs/api-reference/next/head.md) in your pages or components.
- React components outside of `<Main />` will not be initialized by the browser. Do _not_ add application logic here or custom CSS (like `styled-jsx`). If you need shared components in all your pages (like a menu or a toolbar), read [Layouts](/docs/basic-features/layouts.md) intead.
- React components outside of `<Main />` will not be initialized by the browser. Do _not_ add application logic here or custom CSS (like `styled-jsx`). If you need shared components in all your pages (like a menu or a toolbar), read [Layouts](/docs/basic-features/layouts.md) instead.
- `Document` currently does not support Next.js [Data Fetching methods](/docs/basic-features/data-fetching/overview.md) like [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) or [`getServerSideProps`](/docs/basic-features/data-fetching/get-server-side-props.md).

## Customizing `renderPage`
Expand Down
File renamed without changes.
5 changes: 5 additions & 0 deletions examples/with-redis/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
7 changes: 6 additions & 1 deletion examples/with-redis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
"uuid": "^8.3.2"
},
"devDependencies": {
"@tailwindcss/jit": "0.1.1"
"@tailwindcss/jit": "0.1.1",
"@types/ioredis": "4.28.8",
"@types/node": "^16.11.25",
"@types/react": "^17.0.2",
"@types/uuid": "8.3.4",
"typescript": "^4.5.5"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import type { AppProps } from 'next/app'

import '../styles/globals.css'
import { Toaster } from 'react-hot-toast'

function MyApp({ Component, pageProps }) {
function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import type { NextApiRequest, NextApiResponse } from 'next'
import { v4 as uuidv4 } from 'uuid'

import redis from '../../lib/redis'

export default async function create(req, res) {
export default async function create(
req: NextApiRequest,
res: NextApiResponse
) {
const { title } = req.body

if (!title) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { NextApiRequest, NextApiResponse } from 'next'

import redis from '../../lib/redis'

export default async function getAllFeatures(req, res) {
export default async function getAllFeatures(
req: NextApiRequest,
res: NextApiResponse
) {
const features = (await redis.hvals('features'))
.map((entry) => JSON.parse(entry))
.sort((a, b) => b.score - a.score)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { NextApiRequest, NextApiResponse } from 'next'

import redis from '../../lib/redis'

export default async function subscribe(req, res) {
export default async function subscribe(
req: NextApiRequest,
res: NextApiResponse
) {
const { email } = req.body

if (email && validateEmail(email)) {
Expand All @@ -15,7 +20,7 @@ export default async function subscribe(req, res) {
}
}

function validateEmail(email) {
function validateEmail(email: string) {
const re =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return re.test(String(email).toLowerCase())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import type { NextApiRequest, NextApiResponse } from 'next'

import redis from '../../lib/redis'

export default async function upvote(req, res) {
export default async function upvote(
req: NextApiRequest,
res: NextApiResponse
) {
const { title, id } = req.body
const ip =
req.headers['x-forwarded-for'] || req.headers['Remote_Addr'] || 'NA'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { useState, useRef } from 'react'
import type { NextApiRequest } from 'next'
import type { MouseEvent } from 'react'
import Head from 'next/head'
import clsx from 'clsx'
import useSWR, { mutate } from 'swr'
import toast from 'react-hot-toast'
import redis from '../lib/redis'

const fetcher = (url) => fetch(url).then((res) => res.json())
type Feature = {
id: string
title: string
score: number
ip: string
}

const fetcher = (url: string) => fetch(url).then((res) => res.json())

function LoadingSpinner({ invert }) {
function LoadingSpinner({ invert }: { invert?: boolean }) {
return (
<svg
className={clsx(
Expand Down Expand Up @@ -35,8 +44,20 @@ function LoadingSpinner({ invert }) {
)
}

function Item({ isFirst, isLast, isReleased, hasVoted, feature }) {
const upvote = async (e) => {
function Item({
isFirst,
isLast,
isReleased,
hasVoted,
feature,
}: {
isFirst: boolean
isLast: boolean
isReleased: boolean
hasVoted: boolean
feature: Feature
}) {
const upvote = async (e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault()

const res = await fetch('/api/vote', {
Expand Down Expand Up @@ -85,11 +106,17 @@ function Item({ isFirst, isLast, isReleased, hasVoted, feature }) {
)
}

export default function Roadmap({ features, ip }) {
export default function Roadmap({
features,
ip,
}: {
features: Feature[]
ip: string
}) {
const [isCreateLoading, setCreateLoading] = useState(false)
const [isEmailLoading, setEmailLoading] = useState(false)
const featureInputRef = useRef(null)
const subscribeInputRef = useRef(null)
const featureInputRef = useRef<HTMLInputElement>(null)
const subscribeInputRef = useRef<HTMLInputElement>(null)

const { data, error } = useSWR('/api/features', fetcher, {
initialData: { features },
Expand All @@ -99,13 +126,13 @@ export default function Roadmap({ features, ip }) {
toast.error(error)
}

const addFeature = async (e) => {
const addFeature = async (e: MouseEvent<HTMLFormElement>) => {
e.preventDefault()
setCreateLoading(true)

const res = await fetch('/api/create', {
body: JSON.stringify({
title: featureInputRef.current.value,
title: featureInputRef?.current?.value ?? '',
}),
headers: {
'Content-Type': 'application/json',
Expand All @@ -122,16 +149,18 @@ export default function Roadmap({ features, ip }) {
}

mutate('/api/features')
featureInputRef.current.value = ''
if (featureInputRef.current) {
featureInputRef.current.value = ''
}
}

const subscribe = async (e) => {
const subscribe = async (e: MouseEvent<HTMLFormElement>) => {
e.preventDefault()
setEmailLoading(true)

const res = await fetch('/api/subscribe', {
body: JSON.stringify({
email: subscribeInputRef.current.value,
email: subscribeInputRef?.current?.value ?? '',
}),
headers: {
'Content-Type': 'application/json',
Expand All @@ -147,7 +176,10 @@ export default function Roadmap({ features, ip }) {
}

toast.success('You are now subscribed to feature updates!')
subscribeInputRef.current.value = ''

if (subscribeInputRef.current) {
subscribeInputRef.current.value = ''
}
}

return (
Expand Down Expand Up @@ -189,7 +221,7 @@ export default function Roadmap({ features, ip }) {
</form>
</div>
<div className="w-full">
{data.features.map((feature, index) => (
{data.features.map((feature: Feature, index: number) => (
<Item
key={index}
isFirst={index === 0}
Expand Down Expand Up @@ -254,7 +286,7 @@ export default function Roadmap({ features, ip }) {
)
}

export async function getServerSideProps({ req }) {
export async function getServerSideProps({ req }: { req: NextApiRequest }) {
const ip =
req.headers['x-forwarded-for'] || req.headers['Remote_Addr'] || 'NA'
const features = (await redis.hvals('features'))
Expand Down
21 changes: 21 additions & 0 deletions examples/with-redis/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"baseUrl": ".",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"incremental": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
1 change: 0 additions & 1 deletion packages/create-next-app/create-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ export async function createApp({
console.log(`Creating a new Next.js app in ${chalk.green(root)}.`)
console.log()

await makeDir(root)
process.chdir(root)

if (example) {
Expand Down
10 changes: 5 additions & 5 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1848,11 +1848,11 @@ export default async function getBaseWebpackConfig(
}

const fileNames = [
'/tmp/test.css',
'/tmp/test.scss',
'/tmp/test.sass',
'/tmp/test.less',
'/tmp/test.styl',
'/tmp/NEXTJS_CSS_DETECTION_FILE.css',
'/tmp/NEXTJS_CSS_DETECTION_FILE.scss',
'/tmp/NEXTJS_CSS_DETECTION_FILE.sass',
'/tmp/NEXTJS_CSS_DETECTION_FILE.less',
'/tmp/NEXTJS_CSS_DETECTION_FILE.styl',
]

if (rule instanceof RegExp && fileNames.some((input) => rule.test(input))) {
Expand Down