-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from divyenduz/refactor_rsc
refactor(app-router): rewrite to use app router + rsc
- Loading branch information
Showing
91 changed files
with
1,957 additions
and
6,504 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { AwaitedUser } from 'app/layout' | ||
import { checkStravaAccessToken } from 'repository/strava' | ||
import { match } from 'ts-pattern' | ||
|
||
export async function checkStravaToken(user: AwaitedUser) { | ||
if (!user) { | ||
console.error( | ||
'Note: failed to get strava access token, user not found in context' | ||
) | ||
return 'NOT_WORKING' | ||
} | ||
|
||
const socialLogin = user?.socialLogin?.find((sl) => sl.platform === 'STRAVA') | ||
|
||
// Note: if no social login, strava is not connected | ||
if (!Boolean(socialLogin)) { | ||
return 'NOT_CONNECTED' | ||
} | ||
|
||
const r = await checkStravaAccessToken(user.id) | ||
return match(r) | ||
.with(true, () => 'WORKING') | ||
.with(false, () => 'NOT_WORKING') | ||
.exhaustive() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
'use server' | ||
|
||
import { Post, sql } from '@trackfootball/database' | ||
import { MESSAGE_UNAUTHORIZED } from 'packages/auth/utils' | ||
import { auth } from 'utils/auth' | ||
|
||
export async function deletePost(postId: number) { | ||
const user = await auth() | ||
|
||
const post = ( | ||
await sql<Post[]>` | ||
SELECT * FROM "Post" | ||
WHERE "id" = ${postId} | ||
` | ||
)[0] | ||
|
||
if (post?.userId !== user.id && user.type !== 'ADMIN') { | ||
throw new Error(MESSAGE_UNAUTHORIZED) | ||
} | ||
|
||
const deletePost = ( | ||
await sql<Post[]>` | ||
DELETE FROM "Post" | ||
WHERE "id" = ${postId} | ||
RETURNING * | ||
` | ||
)[0] | ||
|
||
return { post: deletePost } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
'use server' | ||
|
||
import { sql } from '@trackfootball/database' | ||
import { revalidatePath } from 'next/cache' | ||
import { auth } from 'utils/auth' | ||
|
||
export async function disconnectStrava() { | ||
const user = await auth() | ||
|
||
const stravaLogin = user.socialLogin.find((sl) => sl.platform === 'STRAVA') | ||
if (!Boolean(stravaLogin)) { | ||
throw new Error("Trying to disconnect Strava login but it doesn't exist") | ||
} | ||
await sql` | ||
DELETE FROM "SocialLogin" | ||
WHERE "id" = ${stravaLogin!.id} | ||
` | ||
revalidatePath(`/athlete/${user.id}`) | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
'use server' | ||
|
||
import { Field, Post, User, sql } from '@trackfootball/database' | ||
import { FeatureCollection, LineString } from '@turf/helpers' | ||
|
||
export type FeedItemType = Post & { | ||
geoJson: FeatureCollection<LineString> | ||
sprints: Array<FeatureCollection<LineString>> | ||
runs: Array<FeatureCollection<LineString>> | ||
Field: Field | ||
User: User | ||
} | ||
|
||
export async function getFeed(cursor: number = 0, limit: number = 3) { | ||
const maxPostId = ( | ||
await sql<{ max: number }[]>`SELECT MAX("id") FROM "Post"` | ||
)[0].max | ||
|
||
const posts = await sql<FeedItemType[]>` | ||
SELECT row_to_json("Field".*::"Field") as "Field", row_to_json("User".*::"User") as "User", "Post".* FROM "Post" | ||
LEFT JOIN "Field" ON "Post"."fieldId" = "Field"."id" | ||
INNER JOIN "User" ON "Post"."userId" = "User"."id" | ||
WHERE "Post"."id" <= ${cursor || maxPostId} | ||
ORDER BY "Post"."startTime" DESC | ||
LIMIT ${limit + 1} | ||
` | ||
|
||
let nextCursor: typeof cursor | null = null | ||
const sortedPosts = posts.slice().sort((a, b) => b.id - a.id) | ||
if (sortedPosts.length > limit) { | ||
const nextItem = sortedPosts.pop() | ||
nextCursor = nextItem!.id | ||
} | ||
|
||
return { posts: sortedPosts, nextCursor } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
'use server' | ||
|
||
import { Post, PostStatus, User, sql } from '@trackfootball/database' | ||
import { Core } from '@trackfootball/sprint-detection' | ||
import { durationToSeconds } from '@trackfootball/utils' | ||
import { MESSAGE_UNAUTHORIZED } from 'packages/auth/utils' | ||
import { postAddField } from 'packages/services/post/addField' | ||
import { fetchStravaActivityGeoJson } from 'repository/strava' | ||
import { auth } from 'utils/auth' | ||
|
||
export async function refreshPost(postId: number) { | ||
const user = await auth() | ||
|
||
const post = ( | ||
await sql<Post[]>` | ||
SELECT * FROM "Post" | ||
WHERE "id" = ${postId} | ||
` | ||
)[0] | ||
|
||
if (post?.userId !== user.id && user.type !== 'ADMIN') { | ||
throw new Error(MESSAGE_UNAUTHORIZED) | ||
} | ||
|
||
const ownerUser = ( | ||
await sql<User[]>` | ||
SELECT * FROM "User" | ||
WHERE "id" = ${post.userId} | ||
` | ||
)[0] | ||
|
||
const _key = parseInt(post.key) | ||
const geoJson = await fetchStravaActivityGeoJson(_key, ownerUser.id) | ||
|
||
if (geoJson instanceof Error) { | ||
throw geoJson | ||
} | ||
|
||
if (!geoJson) { | ||
throw new Error(`No geoJson found for Post id: ${postId}`) | ||
} | ||
const core = new Core(geoJson) | ||
|
||
const updatedPost = ( | ||
await sql<Post[]>` | ||
UPDATE "Post" | ||
SET "geoJson" = ${geoJson as any}, | ||
"totalDistance" = ${core.totalDistance()}, | ||
"startTime" = ${new Date(core.getStartTime())}, | ||
"elapsedTime" = ${durationToSeconds(core.elapsedTime())}, | ||
"totalSprintTime" = ${durationToSeconds(core.totalSprintTime())}, | ||
"sprints" = ${core.sprints() as any}, | ||
"runs" = ${core.runs() as any}, | ||
"maxSpeed" = ${core.maxSpeed()}, | ||
"averageSpeed" = ${core.averageSpeed()}, | ||
"status" = ${PostStatus.COMPLETED} | ||
WHERE "id" = ${postId} | ||
RETURNING * | ||
` | ||
)[0] | ||
|
||
await postAddField({ | ||
postId: post.id, | ||
}) | ||
|
||
return { post: updatedPost } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { Metadata, ResolvingMetadata } from 'next' | ||
import { notFound } from 'next/navigation' | ||
import { auth } from 'utils/auth' | ||
|
||
import ActivityItem from '../../../components/organisms/Activity/ActivityItem' | ||
import { getPost } from '../../../repository/post' | ||
|
||
type Props = { | ||
params: { | ||
id: string | ||
} | ||
} | ||
|
||
export function getHomepageUrl() { | ||
const url = process.env.HOMEPAGE_URL || 'https://trackfootball.app' | ||
return url | ||
} | ||
|
||
export async function generateMetadata( | ||
{ params }: Props, | ||
parent: ResolvingMetadata | ||
): Promise<Metadata> { | ||
const id = params.id | ||
|
||
const post = await getPost(parseInt(id)) | ||
|
||
const homepageUrl = getHomepageUrl() | ||
|
||
const title = `${post?.text} | Activity | TrackFootball` | ||
const description = `${post?.text} is a Football activity on TrackFootball` | ||
const url = `${homepageUrl}/activity/${post?.id}` | ||
const openGraph = { | ||
title, | ||
description, | ||
type: 'website', | ||
url, | ||
} | ||
const twitter = { | ||
title, | ||
description, | ||
card: 'summary_large_image', | ||
site: '@_TrackFootball', | ||
creator: '@_TrackFootball', | ||
domain: 'trackfootball.app', | ||
url, | ||
} | ||
|
||
return { | ||
title, | ||
description, | ||
openGraph, | ||
twitter, | ||
} | ||
} | ||
|
||
export default async function Activity({ params: { id } }: Props) { | ||
const post = await getPost(parseInt(id)) | ||
|
||
if (!post) { | ||
return notFound() | ||
} | ||
|
||
let user = null | ||
try { | ||
user = await auth() | ||
} catch (e) { | ||
console.error(e) | ||
} | ||
|
||
return ( | ||
<> | ||
<div className="w-full max-w-4xl p-3 sm:p-5"> | ||
<ActivityItem post={post} user={user}></ActivityItem> | ||
</div> | ||
</> | ||
) | ||
} |
Oops, something went wrong.