From 0fc6700f097673f6f477f3bc28cc337832b1495b Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:06:07 -0500
Subject: [PATCH 01/16] Fix redis locks from use server access
---
lib/redis-lock.ts | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/redis-lock.ts b/lib/redis-lock.ts
index dfe1b25e..8d793c92 100644
--- a/lib/redis-lock.ts
+++ b/lib/redis-lock.ts
@@ -1,10 +1,11 @@
-'use server'
+import 'server-only'
+
import { kv } from '@vercel/kv'
import { v4 as uuidv4 } from 'uuid'
const LOCK_TIMEOUT = 30 * 1000 // 30 seconds
-export async function aquireLock(key: string): Promise {
+async function aquireLock(key: string): Promise {
const lockKey = `lock:${key}`
const lockValue = uuidv4()
const acquired = await kv.set(lockKey, lockValue, {
@@ -14,7 +15,7 @@ export async function aquireLock(key: string): Promise {
return acquired ? lockValue : null
}
-export async function releaseLock(
+async function releaseLock(
lockKey: string,
lockValue: string,
): Promise {
From 33d3a868ce417279054ed732257e8df9b618bcec Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:06:23 -0500
Subject: [PATCH 02/16] Remove unnecessary use server from marketing page
---
src/app/page.tsx | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/app/page.tsx b/src/app/page.tsx
index ffe9b4fb..99a9bfb5 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,5 +1,3 @@
-'use server'
-
import Marketing from './marketing/page'
export default async function Page() {
From 163005bd61ef3e95891944c4cb76a977ebd27be3 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:27:28 -0500
Subject: [PATCH 03/16] Background jobs don't 'use server'
---
src/app/api/cron/process-background-jobs.ts | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/app/api/cron/process-background-jobs.ts b/src/app/api/cron/process-background-jobs.ts
index c865b5e7..e253363c 100644
--- a/src/app/api/cron/process-background-jobs.ts
+++ b/src/app/api/cron/process-background-jobs.ts
@@ -1,7 +1,6 @@
-'use server'
+import 'server-only'
import { sql } from '@vercel/postgres'
-import Airtable from 'airtable'
async function processPendingInviteJobs() {
const { rows } =
From a6e9fba8f45396072c1f1fa071ffecdc52c54819 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:32:36 -0500
Subject: [PATCH 04/16] Make project ideas route 'server-only'
---
src/app/api/project_ideas/route.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/api/project_ideas/route.ts b/src/app/api/project_ideas/route.ts
index 493b31b1..164e7527 100644
--- a/src/app/api/project_ideas/route.ts
+++ b/src/app/api/project_ideas/route.ts
@@ -1,4 +1,4 @@
-'use server'
+import 'server-only'
import { NextRequest, NextResponse } from 'next/server'
import { sample } from '../../../../lib/flavor'
From b2b589d56f72b42b0d25c4bacdcc912176cc084c Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:33:31 -0500
Subject: [PATCH 05/16] Switch referral autonum to 'server-only'
---
src/app/api/referral/[autonum]/route.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/api/referral/[autonum]/route.ts b/src/app/api/referral/[autonum]/route.ts
index 6f19fb9d..5ddc917c 100644
--- a/src/app/api/referral/[autonum]/route.ts
+++ b/src/app/api/referral/[autonum]/route.ts
@@ -1,4 +1,4 @@
-'use server'
+import 'server-only'
import { getPersonByAuto } from '@/app/utils/airtable'
import { redirect } from 'next/navigation'
From ab144fbb2b6dac9a7334fb43a819d8ca5a54e96b Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:40:11 -0500
Subject: [PATCH 06/16] Check session validity in sendFraudReport
---
src/app/harbor/battles/fraud-utils.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/app/harbor/battles/fraud-utils.ts b/src/app/harbor/battles/fraud-utils.ts
index 81f86cc6..3e559445 100644
--- a/src/app/harbor/battles/fraud-utils.ts
+++ b/src/app/harbor/battles/fraud-utils.ts
@@ -9,6 +9,9 @@ export async function sendFraudReport(
reason: string,
) {
const session = await getSession()
+ if (!session) {
+ throw new Error('Unauthorized request')
+ }
const res = await fetch(
'https://middleman.hackclub.com/airtable/v0/appTeNFYcUiYfGcR6/flagged_projects',
From b3c86d38b279b73922af76363ce20bf2fe188258 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:42:57 -0500
Subject: [PATCH 07/16] Rename battles component to match file name
---
src/app/harbor/battles/battles.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/app/harbor/battles/battles.tsx b/src/app/harbor/battles/battles.tsx
index 33da9921..10393c36 100644
--- a/src/app/harbor/battles/battles.tsx
+++ b/src/app/harbor/battles/battles.tsx
@@ -33,7 +33,7 @@ interface Matchup {
ts: number
}
-export default function Matchups({ session }: { session: HsSession }) {
+export default function Battles({ session }: { session: HsSession }) {
const [matchup, setMatchup] = useState(null)
const [loading, setLoading] = useState(true)
const [selectedProject, setSelectedProject] = useState(null)
From 7203772731a0d3bf9a83e05b05a9162ef6eb263f Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 11:44:57 -0500
Subject: [PATCH 08/16] Remove unused/unaudited gallery code
---
src/app/harbor/gallery/gallery.tsx | 77 ------------------------------
src/app/harbor/gallery/utils.ts | 55 ---------------------
2 files changed, 132 deletions(-)
delete mode 100644 src/app/harbor/gallery/gallery.tsx
delete mode 100644 src/app/harbor/gallery/utils.ts
diff --git a/src/app/harbor/gallery/gallery.tsx b/src/app/harbor/gallery/gallery.tsx
deleted file mode 100644
index 55ad13cc..00000000
--- a/src/app/harbor/gallery/gallery.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-'use client'
-
-import { useEffect, useState, useCallback } from 'react'
-import InfiniteScroll from 'react-infinite-scroll-component'
-import { getShips } from './utils'
-import { Ship } from '../shipyard/ship-utils'
-import Ships from '../shipyard/ships'
-
-export type ShipsObject = Record
-
-export default function Gallery({ ships, setShips }: any) {
- const [nextOffset, setNextOffset] = useState(undefined)
- const [hasMore, setHasMore] = useState(true)
- const [isLoading, setIsLoading] = useState(false)
-
- const fetchShips = useCallback(async () => {
- if (isLoading || !hasMore) return
- setIsLoading(true)
-
- try {
- const newShipInfo = await getShips(nextOffset)
- setNextOffset(newShipInfo.offset)
- setHasMore(!!newShipInfo.offset)
-
- setShips((prev: any) => {
- const newShips = newShipInfo.ships.reduce(
- (acc: ShipsObject, ship: Ship) => {
- acc[ship.id] = ship
- return acc
- },
- {},
- )
- return { ...prev, ...newShips }
- })
- } catch (error) {
- console.error('Error fetching ships:', error)
- setHasMore(false)
- setIsLoading(false)
- } finally {
- setIsLoading(false)
- }
- }, [isLoading, hasMore, nextOffset])
-
- useEffect(() => {
- if (Object.keys(ships).length === 0) {
- fetchShips()
- }
- }, [])
-
- if (!ships) return Loading all ships...
-
- const shipsArray: Ship[] = Object.values(ships)
-
- if (shipsArray.length === 0)
- return Loading all ships...
-
- return (
-
- Loading
-
- }
- endMessage={
-
- Yay! You have seen all {shipsArray.length} ships.
-
- }
- scrollableTarget="harbor-tab-scroll-element"
- >
-
-
- )
-}
diff --git a/src/app/harbor/gallery/utils.ts b/src/app/harbor/gallery/utils.ts
deleted file mode 100644
index de270bb5..00000000
--- a/src/app/harbor/gallery/utils.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-'use server'
-
-import { Ship } from '../shipyard/ship-utils'
-
-interface AirtableShipRow {
- id: string
- fields: {
- title: string
- readme_url: string
- repo_url: string
- screenshot_url: string
- hours: number
- rating: number
- }
-}
-
-export async function getShips(offset: string | undefined): Promise<{
- ships: Ship[]
- offset: string | undefined
-}> {
- const res = await fetch(
- `https://middleman.hackclub.com/airtable/v0/appTeNFYcUiYfGcR6/ships?view=Grid%20view${offset ? `&offset=${offset}` : ''}`,
- {
- headers: {
- Authorization: `Bearer ${process.env.AIRTABLE_API_KEY}`,
- 'User-Agent': 'highseas.hackclub.com (getShips)',
- },
- },
- )
- let data
- try {
- data = await res.json()
- } catch (e) {
- console.error(e, await res.text())
- throw e
- }
-
- // TODO: Error checking
- const ships = data.records.map((r: AirtableShipRow) => {
- return {
- id: r.id,
- title: r.fields.title,
- readmeUrl: r.fields.readme_url,
- hours: r.fields.hours,
- repoUrl: r.fields.repo_url,
- screenshotUrl: r.fields.screenshot_url,
- rating: r.fields.rating,
- }
- })
-
- return {
- ships,
- offset: data.offset,
- }
-}
From 4977680576b5123d2340608a9cc64f59bb020549 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 12:22:23 -0500
Subject: [PATCH 09/16] Fix invite-job overusage of 'use server'
---
src/app/marketing/components/email-submission-form.tsx | 2 +-
src/app/marketing/invite-job.js | 10 +++-------
src/app/marketing/send-invite-job.js | 5 +++++
3 files changed, 9 insertions(+), 8 deletions(-)
create mode 100644 src/app/marketing/send-invite-job.js
diff --git a/src/app/marketing/components/email-submission-form.tsx b/src/app/marketing/components/email-submission-form.tsx
index a7edb400..2a41ebfa 100644
--- a/src/app/marketing/components/email-submission-form.tsx
+++ b/src/app/marketing/components/email-submission-form.tsx
@@ -6,7 +6,7 @@ import { Button } from '../../../components/ui/button'
import Icon from '@hackclub/icons'
import Modal from '../../../components/ui/modal'
import { handleEmailSubmission } from '../marketing-utils'
-import { sendInviteJob } from '../invite-job'
+import { sendInviteJob } from '../send-invite-job'
import { usePlausible } from 'next-plausible'
export default function EmailSubmissionForm() {
diff --git a/src/app/marketing/invite-job.js b/src/app/marketing/invite-job.js
index ffa659f9..410459b6 100644
--- a/src/app/marketing/invite-job.js
+++ b/src/app/marketing/invite-job.js
@@ -1,19 +1,17 @@
-'use server'
-
import { sql } from '@vercel/postgres'
import { headers } from 'next/headers'
-async function sendInviteJob({ email, userAgent }) {
+export async function sendInviteJob({ email, userAgent }) {
const headersList = headers()
const ipAddress = headersList.get('x-forwarded-for')
- const result =
+ const _result =
await sql`INSERT INTO invite_job (email, ip_address, user_agent) VALUES (${email}, ${ipAddress}, ${userAgent});`
// return result;
}
-async function processPendingInviteJobs() {
+export async function processPendingInviteJobs() {
const { rows } =
await sql`SELECT * FROM invite_job WHERE airtable_invite_record_id IS NULL LIMIT 10`
@@ -61,5 +59,3 @@ async function processPendingInviteJobs() {
await sql`UPDATE invite_job SET airtable_invite_record_id = ${id} WHERE email = ${email} AND airtable_invite_record_id IS NULL;`
}
}
-
-export { sendInviteJob, processPendingInviteJobs }
diff --git a/src/app/marketing/send-invite-job.js b/src/app/marketing/send-invite-job.js
new file mode 100644
index 00000000..6e4e497c
--- /dev/null
+++ b/src/app/marketing/send-invite-job.js
@@ -0,0 +1,5 @@
+'use server'
+
+import { sendInviteJob } from './invite-job.js'
+
+export { sendInviteJob }
\ No newline at end of file
From 72b2cebe0cc415cb28609c236d8aee02bb8f5a83 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 12:23:02 -0500
Subject: [PATCH 10/16] Add 'server-only' to invite job
---
src/app/marketing/invite-job.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/app/marketing/invite-job.js b/src/app/marketing/invite-job.js
index 410459b6..d5173508 100644
--- a/src/app/marketing/invite-job.js
+++ b/src/app/marketing/invite-job.js
@@ -1,3 +1,5 @@
+import 'server-only'
+
import { sql } from '@vercel/postgres'
import { headers } from 'next/headers'
From 9cda06486375569b6fba92ba7848e0e7bd539f02 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 13:21:28 -0500
Subject: [PATCH 11/16] Switch airtable.ts & waka.ts to 'server-only'
---
lib/redis-lock.ts | 5 +-
src/app/api/buy/[item]/route.js | 4 +-
src/app/harbor/battles/battles.tsx | 35 +---
src/app/harbor/shipyard/new-ship-form.tsx | 2 +-
src/app/harbor/shipyard/new-update-form.tsx | 2 +-
src/app/harbor/shipyard/ship-utils.ts | 8 +-
src/app/harbor/shipyard/shipyard.tsx | 4 +-
src/app/harbor/shop/shop-utils.ts | 6 +-
src/app/harbor/shop/shop.tsx | 4 +-
src/app/harbor/signpost/leaderboard.tsx | 6 +-
src/app/harbor/signpost/referral.tsx | 4 +-
src/app/harbor/signpost/signpost.tsx | 3 +-
src/app/harbor/tabs/tour.ts | 5 +-
src/app/marketing/send-invite-job.js | 2 +-
src/app/utils/airtable.ts | 40 ++---
src/app/utils/auth.ts | 7 +-
.../utils/get-leaderboard-participating.ts | 3 +
src/app/utils/get-safe-person.ts | 4 +
src/app/utils/get-self-person.ts | 5 +
...t-votes-remaining-for-next-pending-ship.ts | 5 +
src/app/utils/get-waka-sessions.ts | 5 +
.../utils/report-leaderboard-participating.ts | 3 +
src/app/utils/report-tour-step.ts | 5 +
src/app/utils/waka.ts | 163 +-----------------
24 files changed, 85 insertions(+), 245 deletions(-)
create mode 100644 src/app/utils/get-leaderboard-participating.ts
create mode 100644 src/app/utils/get-safe-person.ts
create mode 100644 src/app/utils/get-self-person.ts
create mode 100644 src/app/utils/get-votes-remaining-for-next-pending-ship.ts
create mode 100644 src/app/utils/get-waka-sessions.ts
create mode 100644 src/app/utils/report-leaderboard-participating.ts
create mode 100644 src/app/utils/report-tour-step.ts
diff --git a/lib/redis-lock.ts b/lib/redis-lock.ts
index 8d793c92..66c50045 100644
--- a/lib/redis-lock.ts
+++ b/lib/redis-lock.ts
@@ -15,10 +15,7 @@ async function aquireLock(key: string): Promise {
return acquired ? lockValue : null
}
-async function releaseLock(
- lockKey: string,
- lockValue: string,
-): Promise {
+async function releaseLock(lockKey: string, lockValue: string): Promise {
const currentLockValue = await kv.get(lockKey)
if (currentLockValue === lockValue) {
await kv.del(lockKey)
diff --git a/src/app/api/buy/[item]/route.js b/src/app/api/buy/[item]/route.js
index d8781ca7..ad210e9f 100644
--- a/src/app/api/buy/[item]/route.js
+++ b/src/app/api/buy/[item]/route.js
@@ -1,12 +1,12 @@
import { getSession } from '@/app/utils/auth'
import { redirect } from 'next/navigation'
import { NextResponse } from 'next/server'
-import { getSelfPerson } from '@/app/utils/airtable'
+import { getSelfPerson } from '@/app/utils/get-self-person'
import { base } from 'airtable'
export async function GET(request, { params }) {
const session = await getSession()
- const person = await getSelfPerson(session.slackId)
+ const person = await getSelfPerson()
if (!person) {
return NextResponse.json(
{ error: "i don't even know who you are" },
diff --git a/src/app/harbor/battles/battles.tsx b/src/app/harbor/battles/battles.tsx
index 10393c36..2915141b 100644
--- a/src/app/harbor/battles/battles.tsx
+++ b/src/app/harbor/battles/battles.tsx
@@ -7,10 +7,8 @@ import { AnimatePresence, motion } from 'framer-motion'
import ReactMarkdown from 'react-markdown'
import { LoadingSpinner } from '../../../components/ui/loading_spinner.js'
-import {
- getVotesRemainingForNextPendingShip,
- safePerson,
-} from '@/app/utils/airtable'
+import { getVotesRemainingForNextPendingShip } from '@/app/utils/get-votes-remaining-for-next-pending-ship'
+import { getSafePerson } from '@/app/utils/get-safe-person'
import useLocalStorageState from '../../../../lib/useLocalStorageState'
import { useToast } from '@/hooks/use-toast'
import { HsSession } from '@/app/utils/auth'
@@ -81,7 +79,7 @@ export default function Battles({ session }: { session: HsSession }) {
})
useEffect(() => {
- safePerson().then((sp) => {
+ getSafePerson().then((sp) => {
setCursed(sp.cursed)
setBlessed(sp.blessed)
})
@@ -174,33 +172,8 @@ export default function Battles({ session }: { session: HsSession }) {
}, interval)
}
- // useEffect(() => {
- // if (turnstileRef.current) {
- // let widgetId;
-
- // const genToken = () => {
- // widgetId = window.turnstile!.render(turnstileRef.current, {
- // sitekey: "0x4AAAAAAAzOAaBz1TUgJG68", // Site key
- // theme: "dark",
- // callback: (token: string) => {
- // console.log(token);
- // setTurnstileToken(token);
- // },
- // });
- // };
- // genToken();
-
- // const genTokenInterval = setInterval(genToken, 4 * 60 * 1_000); // Every 4 minutes
-
- // return () => {
- // window.turnstile!.reset(widgetId);
- // clearInterval(genTokenInterval);
- // };
- // }
- // }, [selectedProject]);
-
const fetchVoteBalance = async () => {
- setVoteBalance(await getVotesRemainingForNextPendingShip(session.slackId))
+ setVoteBalance(await getVotesRemainingForNextPendingShip())
}
const fetchMatchup = async (
diff --git a/src/app/harbor/shipyard/new-ship-form.tsx b/src/app/harbor/shipyard/new-ship-form.tsx
index 5821b529..e7e31e77 100644
--- a/src/app/harbor/shipyard/new-ship-form.tsx
+++ b/src/app/harbor/shipyard/new-ship-form.tsx
@@ -5,7 +5,7 @@ import { createShip, Ship } from './ship-utils'
import { Button } from '@/components/ui/button'
import JSConfetti from 'js-confetti'
import { useEffect, useRef, useState } from 'react'
-import { getWakaSessions } from '@/app/utils/waka'
+import { getWakaSessions } from '@/app/utils/get-waka-sessions'
import { AnimatePresence, motion } from 'framer-motion'
import { useToast } from '@/hooks/use-toast'
import Icon from '@hackclub/icons'
diff --git a/src/app/harbor/shipyard/new-update-form.tsx b/src/app/harbor/shipyard/new-update-form.tsx
index 6e72563c..bf837de3 100644
--- a/src/app/harbor/shipyard/new-update-form.tsx
+++ b/src/app/harbor/shipyard/new-update-form.tsx
@@ -4,7 +4,7 @@ import type { Ship } from '@/app/utils/data'
import { Button } from '@/components/ui/button'
import JSConfetti from 'js-confetti'
import { useCallback, useEffect, useRef, useState } from 'react'
-import { getWakaSessions } from '@/app/utils/waka'
+import { getWakaSessions } from '@/app/utils/get-waka-sessions'
import Icon from '@hackclub/icons'
export default function NewUpdateForm({
diff --git a/src/app/harbor/shipyard/ship-utils.ts b/src/app/harbor/shipyard/ship-utils.ts
index 84e0ff2e..83c06b66 100644
--- a/src/app/harbor/shipyard/ship-utils.ts
+++ b/src/app/harbor/shipyard/ship-utils.ts
@@ -1,9 +1,9 @@
'use server'
-import { getSelfPerson } from '@/app/utils/airtable'
+import { getSelfPerson } from '@/app/utils/get-self-person'
import { getSession } from '@/app/utils/auth'
import { fetchShips, person } from '@/app/utils/data'
-import { getWakaSessions } from '@/app/utils/waka'
+import { getWakaSessions } from '@/app/utils/get-waka-sessions'
import { cookies } from 'next/headers'
import type { Ship } from '@/app/utils/data'
import Airtable from 'airtable'
@@ -45,7 +45,7 @@ export async function createShip(formData: FormData, isTutorial: boolean) {
const slackId = session.slackId
return await withLock(`ship:${slackId}`, async () => {
- const entrantId = await getSelfPerson(slackId).then((p) => p.id)
+ const entrantId = await getSelfPerson().then((p) => p.id)
const isShipUpdate = formData.get('isShipUpdate')
@@ -100,7 +100,7 @@ export async function createShipUpdate(
const slackId = session.slackId
return withLock(`update:${slackId}`, async () => {
- const entrantId = await getSelfPerson(slackId).then((p) => p.id)
+ const entrantId = await getSelfPerson().then((p) => p.id)
// This pattern makes sure the ship data is not fraudulent
const ships = await fetchShips(slackId)
diff --git a/src/app/harbor/shipyard/shipyard.tsx b/src/app/harbor/shipyard/shipyard.tsx
index 42e54419..8c7f2e8d 100644
--- a/src/app/harbor/shipyard/shipyard.tsx
+++ b/src/app/harbor/shipyard/shipyard.tsx
@@ -3,7 +3,7 @@
import Ships from './ships'
import useLocalStorageState from '../../../../lib/useLocalStorageState'
import { useEffect } from 'react'
-import { getVotesRemainingForNextPendingShip } from '@/app/utils/airtable'
+import { getVotesRemainingForNextPendingShip } from '@/app/utils/get-votes-remaining-for-next-pending-ship'
import Pill from '@/components/ui/pill'
import { fetchShips, Ship } from '@/app/utils/data'
import { IdeaGenerator } from './idea-generator/impl'
@@ -44,7 +44,7 @@ export default function Shipyard({ session }: any) {
useEffect(() => {
fetchShips(session.slackId).then((ships) => setShips(ships))
- getVotesRemainingForNextPendingShip(session.slackId).then((balance) =>
+ getVotesRemainingForNextPendingShip().then((balance) =>
setVoteBalance(balance),
)
}, [])
diff --git a/src/app/harbor/shop/shop-utils.ts b/src/app/harbor/shop/shop-utils.ts
index 7b357f14..5d36d374 100644
--- a/src/app/harbor/shop/shop-utils.ts
+++ b/src/app/harbor/shop/shop-utils.ts
@@ -2,7 +2,7 @@
import Airtable from 'airtable'
import { getSession } from '@/app/utils/auth'
-import { getSelfPerson } from '@/app/utils/airtable'
+import { getSelfPerson } from '@/app/utils/get-self-person'
import { NextResponse } from 'next/server'
const base = () => {
@@ -37,7 +37,7 @@ export async function getPerson() {
if (!('slackId' in session)) {
return
}
- const person = await getSelfPerson(session.slackId)
+ const person = await getSelfPerson()
if (!person) {
return NextResponse.json(
{ error: "i don't even know who you are" },
@@ -52,7 +52,7 @@ export async function getShop(): Promise {
if (!('slackId' in session)) {
return
}
- const person = await getSelfPerson(session.slackId)
+ const person = await getSelfPerson()
return new Promise((resolve, reject) => {
base()('shop_items')
diff --git a/src/app/harbor/shop/shop.tsx b/src/app/harbor/shop/shop.tsx
index e90227b7..f4feab49 100644
--- a/src/app/harbor/shop/shop.tsx
+++ b/src/app/harbor/shop/shop.tsx
@@ -9,7 +9,7 @@ import JaggedCardSmall from '@/components/jagged-card-small'
import { ShopItemComponent } from './shop-item-component.js'
import { ShopkeeperComponent } from './shopkeeper.js'
-import { safePerson } from '@/app/utils/airtable'
+import { getSafePerson } from '@/app/utils/get-safe-person'
import Progress from './progress.tsx'
export default function Shop({ session }: { session: HsSession }) {
const [filterIndex, setFilterIndex] = useLocalStorageState(
@@ -28,7 +28,7 @@ export default function Shop({ session }: { session: HsSession }) {
useEffect(() => {
setBannerText(sample(shopBanner))
getShop().then((shop) => setShopItems(shop))
- safePerson().then((sp) => setPersonTicketBalance(sp.settledTickets))
+ getSafePerson().then((sp) => setPersonTicketBalance(sp.settledTickets))
}, [])
const [favouriteItems, setFavouriteItems] = useState(
JSON.parse(localStorage.getItem('favouriteItems') ?? '[]'),
diff --git a/src/app/harbor/signpost/leaderboard.tsx b/src/app/harbor/signpost/leaderboard.tsx
index fe90eb16..4e5be2e2 100644
--- a/src/app/harbor/signpost/leaderboard.tsx
+++ b/src/app/harbor/signpost/leaderboard.tsx
@@ -1,10 +1,8 @@
import { Button } from '@/components/ui/button'
import Icon from '@hackclub/icons'
import { useEffect, useState } from 'react'
-import {
- getLeaderboardParticipating,
- reportLeaderboardParticipating,
-} from '@/app/utils/airtable'
+import { getLeaderboardParticipating } from '@/app/utils/get-leaderboard-participating'
+import { reportLeaderboardParticipating } from '@/app/utils/report-leaderboard-participating'
export default function LeaderboardOptIn() {
const [optedIn, setOptedIn] = useState(false)
diff --git a/src/app/harbor/signpost/referral.tsx b/src/app/harbor/signpost/referral.tsx
index e8636b89..66ac8077 100644
--- a/src/app/harbor/signpost/referral.tsx
+++ b/src/app/harbor/signpost/referral.tsx
@@ -10,14 +10,14 @@ import {
PopoverContent,
} from '@/components/ui/popover'
import Icon from '@hackclub/icons'
-import { safePerson } from '@/app/utils/airtable'
+import { getSafePerson } from '@/app/utils/get-safe-person'
export default function Referral() {
const [shareLink, setShareLink] = useState(null)
const [open, setOpen] = useState(false)
useEffect(() => {
- safePerson().then((sp) => {
+ getSafePerson().then((sp) => {
if (sp?.referralLink) {
setShareLink(sp.referralLink)
}
diff --git a/src/app/harbor/signpost/signpost.tsx b/src/app/harbor/signpost/signpost.tsx
index 75eb5467..52b595b5 100644
--- a/src/app/harbor/signpost/signpost.tsx
+++ b/src/app/harbor/signpost/signpost.tsx
@@ -6,10 +6,9 @@ import { motion } from 'framer-motion'
import Verification from './verification'
import Platforms from '@/app/utils/wakatime-setup/platforms'
import JaggedCard from '../../../components/jagged-card'
-import JaggedCardSmall from '@/components/jagged-card-small'
import Cookies from 'js-cookie'
import FeedItems from './feed-items'
-import { getWakaSessions } from '@/app/utils/waka'
+import { getWakaSessions } from '@/app/utils/get-waka-sessions'
import Referral from './referral'
import { getStickyUrls } from './help'
import pluralize from '../../../../lib/pluralize.js'
diff --git a/src/app/harbor/tabs/tour.ts b/src/app/harbor/tabs/tour.ts
index 21ede11a..9782a686 100644
--- a/src/app/harbor/tabs/tour.ts
+++ b/src/app/harbor/tabs/tour.ts
@@ -2,7 +2,8 @@ import Shepherd, { type Tour } from 'shepherd.js'
import './shepherd.css'
import { offset } from '@floating-ui/dom'
import Cookies from 'js-cookie'
-import { reportTourStep, safePerson } from '../../utils/airtable'
+import { reportTourStep } from '@/app/utils/report-tour-step'
+import { getSafePerson } from '@/app/utils/get-safe-person'
const waitForElement = (
selector: string,
@@ -58,7 +59,7 @@ const t = new Shepherd.Tour({
let hasSetUp = false
export function tour() {
- safePerson().then(({ hasCompletedTutorial }) => {
+ getSafePerson().then(({ hasCompletedTutorial }) => {
console.log('Setting tutorial sessionstorage to', hasCompletedTutorial)
sessionStorage.setItem('tutorial', (!hasCompletedTutorial).toString())
})
diff --git a/src/app/marketing/send-invite-job.js b/src/app/marketing/send-invite-job.js
index 6e4e497c..d19c383b 100644
--- a/src/app/marketing/send-invite-job.js
+++ b/src/app/marketing/send-invite-job.js
@@ -2,4 +2,4 @@
import { sendInviteJob } from './invite-job.js'
-export { sendInviteJob }
\ No newline at end of file
+export { sendInviteJob }
diff --git a/src/app/utils/airtable.ts b/src/app/utils/airtable.ts
index ef1c63ff..ab5ee8a1 100644
--- a/src/app/utils/airtable.ts
+++ b/src/app/utils/airtable.ts
@@ -1,19 +1,12 @@
-'use server'
+import 'server-only'
import { getSession } from './auth'
import { person, updateShowInLeaderboard } from './data'
-export const getSelfPerson = async (slackId: string) => {
- const session = await getSession()
- if (!session) {
- throw new Error('No session when trying to get self person')
+export const getPersonBySlackId = async (slackId: string) => {
+ if (!slackId) {
+ throw new Error('No slackId provided')
}
- if (session.slackId !== slackId) {
- const err = new Error('Session slackId does not match provided slackId')
- console.error(err)
- throw err
- }
-
const url = `https://middleman.hackclub.com/airtable/v0/${process.env.BASE_ID}/people`
const filterByFormula = encodeURIComponent(`{slack_id} = '${slackId}'`)
const response = await fetch(`${url}?filterByFormula=${filterByFormula}`, {
@@ -39,6 +32,15 @@ export const getSelfPerson = async (slackId: string) => {
return data.records[0]
}
+export const getSelfPerson = async () => {
+ const session = await getSession()
+ if (!session) {
+ throw new Error('No session when trying to get self person')
+ }
+
+ return getPersonBySlackId(session?.slackId)
+}
+
export const getSignpostUpdates = async () => {
const url = `https://middleman.hackclub.com/airtable/v0/${process.env.BASE_ID}/signpost`
const response = await fetch(url, {
@@ -138,16 +140,14 @@ export async function getPersonByMagicToken(token: string): Promise<{
return { id, email, slackId }
}
-export async function getSelfPersonIdentifier(slackId: string) {
- const person = await getSelfPerson(slackId)
+export async function getSelfPersonIdentifier() {
+ const person = await getSelfPerson()
return person.fields.identifier
}
export const getPersonTicketBalanceAndTutorialStatutWowThisMethodNameSureIsLongPhew =
- async (
- slackId: string,
- ): Promise<{ tickets: number; hasCompletedTutorial: boolean }> => {
- const person = await getSelfPerson(slackId)
+ async (): Promise<{ tickets: number; hasCompletedTutorial: boolean }> => {
+ const person = await getSelfPerson()
const tickets = person.fields.settled_tickets as number
const hasCompletedTutorial = person.fields.academy_completed === true
@@ -155,8 +155,8 @@ export const getPersonTicketBalanceAndTutorialStatutWowThisMethodNameSureIsLongP
}
// deprecate
-export async function getVotesRemainingForNextPendingShip(slackId: string) {
- const person = await getSelfPerson(slackId)
+export async function getVotesRemainingForNextPendingShip() {
+ const person = await getSelfPerson()
return person['fields']['votes_remaining_for_next_pending_ship'] as number
}
@@ -175,7 +175,7 @@ export interface SafePerson {
}
// Good method
-export async function safePerson(): Promise {
+export async function getSafePerson(): Promise {
const record = await person()
const id = record.id
diff --git a/src/app/utils/auth.ts b/src/app/utils/auth.ts
index 63f7cdb8..9051b165 100644
--- a/src/app/utils/auth.ts
+++ b/src/app/utils/auth.ts
@@ -1,7 +1,8 @@
'use server'
import { cookies, headers } from 'next/headers'
-import { getPersonByMagicToken, getSelfPerson } from './airtable'
+import { getPersonByMagicToken } from './airtable'
+import { getPersonBySlackId } from './airtable'
export interface HsSession {
/// The Person record ID in the high seas base
@@ -82,7 +83,7 @@ export async function impersonate(slackId: string) {
}
// look for airtable user with this record
- const person = await getSelfPerson(slackId)
+ const person = await getPersonBySlackId(slackId)
const id = person.id
const email = person.fields.email
@@ -124,7 +125,7 @@ export async function createSlackSession(slackOpenidToken: string) {
if (!payload) throw new Error('Failed to decode the Slack OpenId JWT')
- let person = (await getSelfPerson(payload.sub as string)) as any
+ let person = (await getPersonBySlackId(payload.sub as string)) as any
if (!person) {
const body = JSON.stringify({
diff --git a/src/app/utils/get-leaderboard-participating.ts b/src/app/utils/get-leaderboard-participating.ts
new file mode 100644
index 00000000..f0a35149
--- /dev/null
+++ b/src/app/utils/get-leaderboard-participating.ts
@@ -0,0 +1,3 @@
+'use server'
+import { getLeaderboardParticipating } from './airtable'
+export { getLeaderboardParticipating }
diff --git a/src/app/utils/get-safe-person.ts b/src/app/utils/get-safe-person.ts
new file mode 100644
index 00000000..cb32c397
--- /dev/null
+++ b/src/app/utils/get-safe-person.ts
@@ -0,0 +1,4 @@
+'use server'
+
+import { getSafePerson } from './airtable'
+export { getSafePerson }
diff --git a/src/app/utils/get-self-person.ts b/src/app/utils/get-self-person.ts
new file mode 100644
index 00000000..721b1ee0
--- /dev/null
+++ b/src/app/utils/get-self-person.ts
@@ -0,0 +1,5 @@
+'use server'
+
+import { getSelfPerson } from './airtable'
+
+export { getSelfPerson }
diff --git a/src/app/utils/get-votes-remaining-for-next-pending-ship.ts b/src/app/utils/get-votes-remaining-for-next-pending-ship.ts
new file mode 100644
index 00000000..3f242590
--- /dev/null
+++ b/src/app/utils/get-votes-remaining-for-next-pending-ship.ts
@@ -0,0 +1,5 @@
+'use server'
+
+import { getVotesRemainingForNextPendingShip } from './airtable'
+
+export { getVotesRemainingForNextPendingShip }
diff --git a/src/app/utils/get-waka-sessions.ts b/src/app/utils/get-waka-sessions.ts
new file mode 100644
index 00000000..925478b3
--- /dev/null
+++ b/src/app/utils/get-waka-sessions.ts
@@ -0,0 +1,5 @@
+'use server'
+
+import { getWakaSessions } from '@/app/utils/waka'
+
+export { getWakaSessions }
diff --git a/src/app/utils/report-leaderboard-participating.ts b/src/app/utils/report-leaderboard-participating.ts
new file mode 100644
index 00000000..92f149e0
--- /dev/null
+++ b/src/app/utils/report-leaderboard-participating.ts
@@ -0,0 +1,3 @@
+'use server'
+import { reportLeaderboardParticipating } from './airtable'
+export { reportLeaderboardParticipating }
diff --git a/src/app/utils/report-tour-step.ts b/src/app/utils/report-tour-step.ts
new file mode 100644
index 00000000..d2867247
--- /dev/null
+++ b/src/app/utils/report-tour-step.ts
@@ -0,0 +1,5 @@
+'use server'
+
+import { reportTourStep } from './airtable'
+
+export { reportTourStep }
diff --git a/src/app/utils/waka.ts b/src/app/utils/waka.ts
index b0867ff3..e9bf5263 100644
--- a/src/app/utils/waka.ts
+++ b/src/app/utils/waka.ts
@@ -1,8 +1,6 @@
-'use server'
+import 'server-only'
-import { cookies, headers } from 'next/headers'
-import { redirect } from 'next/navigation'
-import { getSession, HsSession } from './auth'
+import { getSession } from './auth'
import { fetchWaka } from './data'
const WAKA_API_KEY = process.env.WAKA_API_KEY
@@ -17,110 +15,6 @@ export interface WakaInfo {
key: string
}
-// Moved
-// export async function waka(): Promise {
-// return new Promise(async (resolve, reject) => {
-// const p = await person();
-// const {
-// wakatime_username,
-// wakatime_key,
-// slack_id,
-// email,
-// name,
-// preexistingUser,
-// } = p.fields;
-
-// if (wakatime_key && wakatime_username) {
-// const info = {
-// username: wakatime_username,
-// key: wakatime_key,
-// };
-// console.log("[waka::waka] From Airtable:", info);
-// return resolve(info);
-// }
-
-// const legacyKeyRaw = cookies().get("waka-key")?.value as string | undefined;
-// if (preexistingUser && slack_id && legacyKeyRaw) {
-// let legacyKey;
-// try {
-// legacyKey = JSON.parse(legacyKeyRaw);
-// } catch {
-// const error = new Error(
-// `Could not parse legacy cookie: ${legacyKeyRaw}`,
-// );
-// console.error(error);
-// throw error;
-// }
-
-// const info = {
-// username: slack_id,
-// key: legacyKey.api_key,
-// };
-// console.log("[waka::waka] From legacy:", info);
-// return resolve(info);
-// }
-
-// // Create
-// const newWakaInfo = await createWaka(email, name ?? null, slack_id ?? null);
-
-// // Add to person record
-// const res = await fetch(
-// `https://middleman.hackclub.com/airtable/v0/appTeNFYcUiYfGcR6/people`,
-// {
-// method: "PATCH",
-// headers: {
-// Authorization: `Bearer ${process.env.AIRTABLE_API_KEY}`,
-// "Content-Type": "application/json",
-// },
-// body: JSON.stringify({
-// records: [
-// {
-// id: p.id,
-// fields: {
-// wakatime_username: newWakaInfo.username,
-// wakatime_key: newWakaInfo.key,
-// },
-// },
-// ],
-// }),
-// },
-// ).then((d) => d.json());
-
-// console.log("[waka::waka] From created:", newWakaInfo);
-// return resolve(newWakaInfo);
-// });
-// }
-
-// Deprecated
-// export async function getWaka(): Promise {
-// let key = cookies().get("waka-key");
-// if (!key) {
-// const session = await getSession();
-
-// if (!session?.email)
-// throw new Error("You can't make a wakatime account without an email!");
-
-// await createWaka(session.email, session?.name ?? null, session?.slackId);
-// console.log("Created a wakatime account from getWaka. Session: ", session);
-// key = cookies().get("waka-key");
-// if (!key) return null;
-// }
-
-// return JSON.parse(key.value) as WakaSignupResponse;
-// }
-
-// Deprecated
-// async function setWaka(username: string, resp: WakaSignupResponse) {
-// cookies().set("waka-key", JSON.stringify(resp), {
-// secure: process.env.NODE_ENV !== "development",
-// httpOnly: true,
-// });
-// cookies().set("waka-username", JSON.stringify(username), {
-// secure: process.env.NODE_ENV !== "development",
-// httpOnly: true,
-// });
-// }
-
// Good function
export async function createWaka(
email: string,
@@ -129,12 +23,6 @@ export async function createWaka(
): Promise {
const password = crypto.randomUUID()
- // if (!slackId) {
- // const err = new Error("No slack ID found while trying to create WakaTime");
- // console.error(err);
- // throw err;
- // }
-
const payload = {
location: 'America/New_York',
email,
@@ -208,50 +96,3 @@ export async function getWakaSessions(interval?: string): Promise<{
return summaryResJson
}
-
-// export async function hasRecvFirstHeartbeat(): Promise {
-// try {
-// const session = await getSession();
-// if (!session)
-// throw new Error(
-// "No Slack OAuth session found while trying to get WakaTime sessions.",
-// );
-
-// const slackId = session.slackId;
-
-// const hasDataRes: { hasData: boolean } = await fetch(
-// `https://waka.hackclub.com/api/special/hasData/?user=${slackId}`,
-// {
-// headers: {
-// Authorization: `Bearer ${WAKA_API_KEY}`,
-// },
-// },
-// ).then((res) => res.json());
-
-// return hasDataRes.hasData;
-// } catch (e) {
-// console.error(e);
-// return false;
-// }
-// }
-
-// export async function getWakaEmail(): Promise {
-// const session = await getSession();
-// if (!session)
-// throw new Error(
-// "No Slack OAuth session found while trying to get WakaTime sessions.",
-// );
-
-// const slackId = session.slackId;
-
-// const email: { email: string | null } = await fetch(
-// `https://waka.hackclub.com/api/special/email/?user=${slackId}`,
-// {
-// headers: {
-// Authorization: `Bearer ${WAKA_API_KEY}`,
-// },
-// },
-// ).then((res) => res.json());
-
-// return email.email;
-// }
From bad7181dba02db059e2880791801f101e75ca273 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 13:21:37 -0500
Subject: [PATCH 12/16] Remove unused import/export
---
src/app/harbor/signpost/help.ts | 7 -------
1 file changed, 7 deletions(-)
diff --git a/src/app/harbor/signpost/help.ts b/src/app/harbor/signpost/help.ts
index 697d6136..966c43b5 100644
--- a/src/app/harbor/signpost/help.ts
+++ b/src/app/harbor/signpost/help.ts
@@ -5,13 +5,6 @@ const base = new Airtable({ apiKey: process.env.AIRTABLE_API_KEY }).base(
process.env.BASE_ID!,
)
-//TODO: Delete this file it's weird
-import { getWakaSessions } from '@/app/utils/waka'
-
-export async function wakaSessions() {
- return await getWakaSessions()
-}
-
export async function getStickyUrls(): string[] {
const allStickies = (await base('sticky_holidays').select({}).all()).sort(
(a, b) => a.fields.id - b.fields.id,
From bdfea9fc7012eb2a97bcb3254cc4288bf8e2a8f7 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 13:28:08 -0500
Subject: [PATCH 13/16] Delete tutorial-utils.ts
---
.../utils/wakatime-setup/tutorial-utils.ts | 24 -------------------
1 file changed, 24 deletions(-)
delete mode 100644 src/app/utils/wakatime-setup/tutorial-utils.ts
diff --git a/src/app/utils/wakatime-setup/tutorial-utils.ts b/src/app/utils/wakatime-setup/tutorial-utils.ts
deleted file mode 100644
index 080c9e54..00000000
--- a/src/app/utils/wakatime-setup/tutorial-utils.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-'use server'
-
-import { getSession } from '../../utils/auth'
-
-// export async function hasHb(username: string, key: string): Promise {
-// if (!username)
-// throw new Error("Username is undefined while checking waka hasData");
-
-// const res = await fetch(
-// `https://waka.hackclub.com/api/special/hasData?user=${username}`,
-// { headers: { Authorization: `Bearer ${process.env.WAKA_API_KEY}` } },
-// );
-// if (!res.ok) {
-// const txt = await res.text();
-// const err = new Error(
-// `Error while checking ${username}'s waka hasData: ${txt}`,
-// );
-// console.error(err);
-// throw err;
-// }
-
-// const resJson = await res.json();
-// return resJson.hasData === true;
-// }
From 27e660f047210a21feb95c26e8667772fc50e89c Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 13:28:48 -0500
Subject: [PATCH 14/16] Switch auth.ts from 'use server' -> 'server-only'
---
src/app/[tab]/page.tsx | 3 ++-
src/app/harbor/shipyard/ships.tsx | 3 ++-
src/app/harbor/tabs/tabs.tsx | 3 ++-
src/app/utils/auth.ts | 2 +-
src/app/utils/create-magic-session.ts | 4 ++++
src/app/utils/get-session.ts | 4 ++++
6 files changed, 15 insertions(+), 4 deletions(-)
create mode 100644 src/app/utils/create-magic-session.ts
create mode 100644 src/app/utils/get-session.ts
diff --git a/src/app/[tab]/page.tsx b/src/app/[tab]/page.tsx
index 69415b58..bdd7c110 100644
--- a/src/app/[tab]/page.tsx
+++ b/src/app/[tab]/page.tsx
@@ -2,7 +2,8 @@
import { notFound } from 'next/navigation'
import Harbor from '../harbor/tabs/tabs'
-import { createMagicSession, getSession } from '../utils/auth'
+import { createMagicSession } from '../utils/create-magic-session'
+import { getSession } from '../utils/get-session'
import { Card } from '@/components/ui/card'
import { SoundButton } from '../../components/sound-button.js'
import { useEffect } from 'react'
diff --git a/src/app/harbor/shipyard/ships.tsx b/src/app/harbor/shipyard/ships.tsx
index 7bbd1a58..d5bff3b1 100644
--- a/src/app/harbor/shipyard/ships.tsx
+++ b/src/app/harbor/shipyard/ships.tsx
@@ -11,7 +11,8 @@ import { markdownComponents } from '@/components/markdown'
import { Button, buttonVariants } from '@/components/ui/button'
import NewShipForm from './new-ship-form'
import EditShipForm from './edit-ship-form'
-import { getSession, HsSession } from '@/app/utils/auth'
+import { type HsSession } from '@/app/utils/auth'
+import { getSession } from '@/app/utils/get-session'
import Link from 'next/link'
import TimeAgo from 'javascript-time-ago'
import ShipPillCluster from '@/components/ui/ship-pill-cluster'
diff --git a/src/app/harbor/tabs/tabs.tsx b/src/app/harbor/tabs/tabs.tsx
index f42b6897..1380b523 100644
--- a/src/app/harbor/tabs/tabs.tsx
+++ b/src/app/harbor/tabs/tabs.tsx
@@ -10,7 +10,8 @@ import SignPost from '../signpost/signpost'
import { tour } from './tour'
import useLocalStorageState from '../../../../lib/useLocalStorageState'
import { useRouter } from 'next/navigation'
-import { getSession, type HsSession } from '@/app/utils/auth'
+import { type HsSession } from '@/app/utils/auth'
+import { getSession } from '@/app/utils/get-session'
import {
Popover,
PopoverTrigger,
diff --git a/src/app/utils/auth.ts b/src/app/utils/auth.ts
index 9051b165..a4cfdcf2 100644
--- a/src/app/utils/auth.ts
+++ b/src/app/utils/auth.ts
@@ -1,4 +1,4 @@
-'use server'
+import 'server-only'
import { cookies, headers } from 'next/headers'
import { getPersonByMagicToken } from './airtable'
diff --git a/src/app/utils/create-magic-session.ts b/src/app/utils/create-magic-session.ts
new file mode 100644
index 00000000..bc63fffb
--- /dev/null
+++ b/src/app/utils/create-magic-session.ts
@@ -0,0 +1,4 @@
+'use server'
+
+import { createMagicSession } from './auth'
+export { createMagicSession }
diff --git a/src/app/utils/get-session.ts b/src/app/utils/get-session.ts
new file mode 100644
index 00000000..a4c6564f
--- /dev/null
+++ b/src/app/utils/get-session.ts
@@ -0,0 +1,4 @@
+'use server'
+
+import { getSession } from './auth'
+export { getSession }
From 026860021022da132acbe66d9d28c22f5370f233 Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 13:30:44 -0500
Subject: [PATCH 15/16] Remove unused 'use server' from sign_in.tsx
---
src/components/sign_in.tsx | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/components/sign_in.tsx b/src/components/sign_in.tsx
index eb776b03..ca189e59 100644
--- a/src/components/sign_in.tsx
+++ b/src/components/sign_in.tsx
@@ -1,6 +1,3 @@
-'use server'
-
-import { buttonVariants } from '@/components/ui/button'
import { headers } from 'next/headers'
export default async function SignIn({
From d57f46f335d09adc6cba9cc19350b9e9f5baec5e Mon Sep 17 00:00:00 2001
From: Max Wofford
Date: Thu, 2 Jan 2025 13:32:20 -0500
Subject: [PATCH 16/16] Remove unused 'use server' from nav.tsx
---
src/components/nav.tsx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/components/nav.tsx b/src/components/nav.tsx
index ca7a1bcd..9c0c1c10 100644
--- a/src/components/nav.tsx
+++ b/src/components/nav.tsx
@@ -1,6 +1,4 @@
-'use server'
-
-import { getSession } from '@/app/utils/auth'
+import { getSession } from '@/app/utils/get-session'
import SignOut from './sign_out'
import SignIn from './sign_in'
import Image from 'next/image'