Skip to content

Commit

Permalink
Initial commit from Create Next App
Browse files Browse the repository at this point in the history
  • Loading branch information
kamikazebr committed Jun 28, 2023
0 parents commit 7fc5078
Show file tree
Hide file tree
Showing 19 changed files with 3,435 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# Dependencies
/node_modules
/.pnp
.pnp.js

# Testing
/coverage

# Next.js
/.next/
/out/

# Production
/build

# Misc
.DS_Store
*.pem

# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Local ENV files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Vercel
.vercel

# Turborepo
.turbo

# typescript
*.tsbuildinfo
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: Vercel Cron Job Example
slug: vercel-cron
description: A Next.js app that uses Vercel Cron Jobs to update data at different intervals.
framework: Next.js
useCase:
- Cron
- Edge Functions
css: Tailwind
database: Vercel KV
deployUrl: https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fsolutions%2Fcron&project-name=cron&repository-name=cron&demo-title=Vercel%20Cron%20Job%20Example&demo-description=A%20Next.js%20app%20that%20uses%20Vercel%20Cron%20Jobs%20to%20update%20data%20at%20different%20intervals.&demo-url=https%3A%2F%2Fcron-template.vercel.app%2F&demo-image=https%3A%2F%2Fcron-template.vercel.app%2Fthumbnail.png&stores=%5B%7B"type"%3A"kv"%7D%5D
demoUrl: https://cron-template.vercel.app/
relatedTemplates:
- hacker-news-slack-bot
- cron-og
---

# Vercel Cron Job Example

A Next.js app that uses [Vercel Cron Jobs](https://vercel.com/docs/cron-jobs) to update data at different intervals.

## Demo

https://cron-template.vercel.app/

## How to Use

You can choose from one of the following two methods to use this repository:

### One-Click Deploy

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=examples-repo):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fsolutions%2Fcron&project-name=cron&repository-name=cron&demo-title=Vercel%20Cron%20Job%20Example&demo-description=A%20Next.js%20app%20that%20uses%20Vercel%20Cron%20Jobs%20to%20update%20data%20at%20different%20intervals.&demo-url=https%3A%2F%2Fcron-template.vercel.app%2F&demo-image=https%3A%2F%2Fcron-template.vercel.app%2Fthumbnail.png&stores=%5B%7B"type"%3A"kv"%7D%5D)

Don't forget to set the required environment variables that you got from the previous step.

### Clone and Deploy

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [pnpm](https://pnpm.io/installation) to bootstrap the example:

```bash
pnpm create next-app --example https://github.com/vercel/examples/tree/main/solutions/cron cron
```

Next, run Next.js in development mode:

```bash
pnpm dev
```

Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=examples-repo) ([Documentation](https://nextjs.org/docs/deployment)).
81 changes: 81 additions & 0 deletions components/post.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import ms from 'ms'
import useSWR from 'swr'

interface DataProps {
id: number
title: string
by: string
time: number
score: number
descendants: number
fetchedAt: number
}

export default function Post({ interval }: { interval: string }) {
const { data } = useSWR<DataProps>(`/api/data/${interval}`, (url) =>
fetch(url).then((res) => res.json())
)

if (!data)
return (
<div className="flex justify-between items-center border border-gray-100 shadow-md rounded-lg p-5">
<div className="grid gap-3">
<div className="bg-gray-200 animate-pulse rounded-md w-96 h-6" />
<div className="bg-gray-200 animate-pulse rounded-md w-60 h-4" />
</div>
<div className="bg-gray-200 animate-pulse rounded-md w-28 h-4" />
</div>
)

const { id, title, by, time, score, descendants, fetchedAt } = data || {}
return (
<div className="flex justify-between items-center border border-gray-100 shadow-md rounded-lg p-5">
<div className="grid gap-2">
<a
href={`https://news.ycombinator.com/item?id=${id}`}
target="_blank"
rel="noreferrer noopener"
>
<h3 className="text-gray-600 hover:text-black font-semibold transition-all">
{title}
</h3>
</a>
<div className="flex space-x-1 text-gray-500 text-sm">
<a
href={`https://news.ycombinator.com/item?id=${id}`}
target="_blank"
rel="noreferrer noopener"
className="hover:underline hover:text-gray-800 transition-all"
>
{score} {score === 1 ? 'point' : 'points'}
</a>
<p>by</p>
<a
href={`https://news.ycombinator.com/user?id=${by}/`}
target="_blank"
rel="noreferrer noopener"
className="hover:underline hover:text-gray-800 transition-all"
>
{by}
</a>
<p>{timeAgo(time * 1000)}</p>
<p>|</p>
<a
href={`https://news.ycombinator.com/item?id=${id}`}
target="_blank"
rel="noreferrer noopener"
className="hover:underline hover:text-gray-800 transition-all"
>
{descendants} {descendants === 1 ? 'comment' : 'comments'}
</a>
</div>
</div>
<p className="text-gray-500 text-sm">fetched {timeAgo(fetchedAt)}</p>
</div>
)
}

const timeAgo = (time: number): string => {
if (!time) return 'Never'
return `${ms(Date.now() - new Date(time).getTime())} ago`
}
5 changes: 5 additions & 0 deletions 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.
34 changes: 34 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "cron",
"repository": "https://github.com/vercel/examples.git",
"license": "MIT",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@vercel/analytics": "^0.1.11",
"@vercel/examples-ui": "^1.0.5",
"@vercel/kv": "^0.2.1",
"ms": "^2.1.3",
"next": "canary",
"react": "latest",
"react-dom": "latest",
"swr": "^2.1.0"
},
"devDependencies": {
"@types/ms": "^0.7.31",
"@types/node": "^17.0.45",
"@types/react": "18.0.27",
"autoprefixer": "^10.4.14",
"eslint": "^8.36.0",
"eslint-config-next": "canary",
"postcss": "^8.4.21",
"tailwindcss": "^3.2.7",
"turbo": "^1.8.3",
"typescript": "4.9.5"
}
}
27 changes: 27 additions & 0 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { AppProps } from 'next/app'
import type { LayoutProps } from '@vercel/examples-ui/layout'
import { Analytics } from '@vercel/analytics/react'

import { getLayout } from '@vercel/examples-ui'
import '@vercel/examples-ui/globals.css'

function App({ Component, pageProps }: AppProps) {
const Layout = getLayout<LayoutProps>(Component)

return (
<Layout
title="Vercel Cron Job Example"
deployButton={{
customDeployUrl:
'https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fexamples%2Ftree%2Fmain%2Fsolutions%2Fcron&project-name=cron&repository-name=cron&demo-title=Vercel%20Cron%20Job%20Example&demo-description=A%20Next.js%20app%20that%20uses%20Vercel%20Cron%20Jobs%20to%20update%20data%20at%20different%20intervals.&demo-url=https%3A%2F%2Fcron-template.vercel.app%2F&demo-image=https%3A%2F%2Fcron-template.vercel.app%2Fthumbnail.png&integration-ids=oac_V3R1GIpkoJorr6fqyiwdhl17',
}}
path="solutions/cron"
description="How to use Vercel Cron Jobs to update data at different intervals"
>
<Component {...pageProps} />
<Analytics />
</Layout>
)
}

export default App
13 changes: 13 additions & 0 deletions pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Head, Html, Main, NextScript } from 'next/document'

export default function Document() {
return (
<Html lang="en">
<Head />
<body className="bg-white dark:bg-black">
<Main />
<NextScript />
</body>
</Html>
)
}
29 changes: 29 additions & 0 deletions pages/api/cron/[cron].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { NextRequest, NextResponse } from 'next/server'
import { kv } from '@vercel/kv'

export const config = {
runtime: 'edge',
}

export default async function handler(req: NextRequest) {
const cron = req.nextUrl.pathname.split('/')[3]
console.log(cron)
if (!cron) return new Response('No cron provided', { status: 400 })
const response = await update(cron)
return new NextResponse(JSON.stringify(response), {
status: 200,
})
}

async function update(interval: string) {
const topstories = await fetch(
'https://hacker-news.firebaseio.com/v0/newstories.json?print=pretty'
).then((res) => res.json())

const response = await kv.set(interval, {
fetchedAt: Date.now(),
id: topstories[0],
})

return response
}
28 changes: 28 additions & 0 deletions pages/api/data/[interval].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NextRequest, NextResponse } from 'next/server'
import { kv } from '@vercel/kv'

export const config = {
runtime: 'edge',
}

export default async function handler(req: NextRequest) {
const interval = req.nextUrl.searchParams.get('interval')
if (!interval) return new Response('No interval provided', { status: 400 })
const { id, fetchedAt } =
(await kv.get<{
id: string
fetchedAt: string
} | null>(interval)) || {}
const res = await fetch(
`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`
).then((res) => res.json())
return new NextResponse(
JSON.stringify({
fetchedAt,
...res,
}),
{
status: 200,
}
)
}
Loading

0 comments on commit 7fc5078

Please sign in to comment.