Skip to content

Commit

Permalink
[SOA-46] Open Graph Tags (#47)
Browse files Browse the repository at this point in the history
* feat 🎸 (SEO): add abstracted head with open graph

* test 🧪 (routes): refactor browser tests with izzy routes

* fix ✅ : tag corrections

* fix ✅ : domain url env as an inertia shared prop
  • Loading branch information
mariadriana-deemaze authored Nov 29, 2024
1 parent 9a398d6 commit 4af0381
Show file tree
Hide file tree
Showing 17 changed files with 154 additions and 36 deletions.
2 changes: 2 additions & 0 deletions config/inertia.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { UserResponse } from '#interfaces/user'
import { UserService } from '#services/user_service'
import env from '#start/env'
import { defineConfig } from '@adonisjs/inertia'
import type { InferSharedProps } from '@adonisjs/inertia/types'

Expand All @@ -24,6 +25,7 @@ const inertiaConfig = defineConfig({
},
queryParams: (ctx) => ctx.request.qs(),
errors: (ctx) => ctx.session?.flashMessages.get('errors'),
domain: () => env.get('PRODUCTION_URL'),
},

/**
Expand Down
27 changes: 27 additions & 0 deletions inertia/components/generic/head_og.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Head, usePage } from '@inertiajs/react'
import socialAdonisLogo from '../../../public/assets/images/thumbnail.png'

interface HeadOGProps {
title: string
description: string
url: string
image?: string
}

export default function HeadOG({ title, description, image, url }: HeadOGProps) {
const props = usePage().props

const domain = props.domain

return (
<Head title={title}>
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image || domain + socialAdonisLogo} />
<meta property="og:url" content={domain + url} />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Social Adonis" />
<meta property="og:locale" content="en_US" />
</Head>
)
}
2 changes: 1 addition & 1 deletion inertia/components/users/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default function UserNavBar({ user }: { user: UserResponse | null }) {
>
<Link
className="flex flex-row items-center relative w-full"
href={route('settings.show', { params: { id: user?.id! } }).path}
href={route('settings.show').path}
>
Settings
<DropdownMenuShortcut className="absolute right-0">
Expand Down
8 changes: 6 additions & 2 deletions inertia/pages/feed.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { route } from '@izzyjs/route/client'
import { Head } from '@inertiajs/react'
import { CreatePost } from '@/components/posts/create'
import FeedList from '@/components/posts/feed_list'
import type { InferPageProps } from '@adonisjs/inertia/types'
import type FeedController from '#controllers/feed_controller'
import HeadOG from '@/components/generic/head_og'

export default function Feed({ posts, user }: InferPageProps<FeedController, 'index'>) {
return (
<>
<Head title="Feed" />
<HeadOG
title="Feed"
description="Discover the best creators on Social Adonis."
url={route('feed.show').path}
/>
<FeedList url={route('feed.show').path} currentUser={user} posts={posts} />
{user && (
<div className="z-10 fixed left-5 bottom-5">
Expand Down
9 changes: 7 additions & 2 deletions inertia/pages/home.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Head, Link } from '@inertiajs/react'
import { Link } from '@inertiajs/react'
import { route } from '@izzyjs/route/client'
import { Button } from '@/components/ui/button'
import AdonisLogo from '@/components/svg/logo'
import HeadOG from '@/components/generic/head_og'

export default function Home() {
return (
<>
<Head title="Homepage" />
<HeadOG
title="Homepage"
description="Homepage of social adonis."
url={route('home.show').path}
/>
<div className="container gap-8">
<AdonisLogo />
<div className="title">Landing page</div>
Expand Down
9 changes: 7 additions & 2 deletions inertia/pages/posts/show.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import PostsController from '#controllers/posts_controller'
import { PostStatus } from '#enums/post'
import HeadOG from '@/components/generic/head_og'
import InfoPanel from '@/components/generic/info_panel'
import PostCard from '@/components/posts/post_card'
import { Button } from '@/components/ui/button'
import { InferPageProps } from '@adonisjs/inertia/types'
import { Head, router } from '@inertiajs/react'
import { router } from '@inertiajs/react'
import { route } from '@izzyjs/route/client'
import { MoveLeft } from 'lucide-react'

export default function Show({ post, user }: InferPageProps<PostsController, 'show'>) {
if (!post) return <>loading...</>
return (
<>
<Head title={`Post by @${post.user.username}`} />
<HeadOG
title={`Post by @${post.user.username}`}
description={post.content}
url={route('posts.show', { params: { id: post.id } }).path}
/>
<div className="w-full flex flex-col items-start pb-4">
<div className="my-6">
<div
Expand Down
9 changes: 7 additions & 2 deletions inertia/pages/sign_in.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useEffect } from 'react'
import { Head, Link, useForm } from '@inertiajs/react'
import { Link, useForm } from '@inertiajs/react'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useToast } from '@/components/ui/use_toast'
import AdonisLogo from '@/components/svg/logo'
import { route } from '@izzyjs/route/client'
import HeadOG from '@/components/generic/head_og'

export default function SignIn() {
const { toast } = useToast()
Expand All @@ -29,7 +30,11 @@ export default function SignIn() {

return (
<>
<Head title="Sign in" />
<HeadOG
title="Sign in"
description="Sign in to social adonis."
url={route('auth.show').path}
/>
<div className="container gap-10">
<AdonisLogo />
<form className="flex flex-col items-center gap-4" onSubmit={handleSubmit}>
Expand Down
9 changes: 7 additions & 2 deletions inertia/pages/sign_up.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect } from 'react'
import { Head, Link, useForm } from '@inertiajs/react'
import { Link, useForm } from '@inertiajs/react'
import HeadOG from '@/components/generic/head_og'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
Expand Down Expand Up @@ -31,7 +32,11 @@ export default function SignUp() {

return (
<>
<Head title="Sign up" />
<HeadOG
title="Sign up"
description="Sign up to social adonis."
url={route('auth.store').path}
/>
<div className="container gap-10">
<AdonisLogo />
<form className="flex flex-col items-center gap-4" onSubmit={handleSubmit}>
Expand Down
9 changes: 7 additions & 2 deletions inertia/pages/users/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import UsersController from '#controllers/users_controller'
import { UserResponse } from '#interfaces/user'
import HeadOG from '@/components/generic/head_og'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
Expand All @@ -8,7 +9,7 @@ import { Label } from '@/components/ui/label'
import { useToast } from '@/components/ui/use_toast'
import { cn } from '@/lib/utils'
import { InferPageProps } from '@adonisjs/inertia/types'
import { Head, useForm, usePage } from '@inertiajs/react'
import { useForm, usePage } from '@inertiajs/react'
import { route } from '@izzyjs/route/client'
import { AtSign, Upload } from 'lucide-react'
import { ChangeEvent, useEffect, useRef, useState } from 'react'
Expand Down Expand Up @@ -93,7 +94,11 @@ export default function UserSettings({

return (
<>
<Head title={`${user.username} Setting's`} />
<HeadOG
title={`${user.username} Setting's`}
description="Your profile settings on Social Adonis."
url={route('settings.show').path}
/>
<div className="relative flex flex-col pt-0 w-full">
<form className="flex flex-col items-center gap-4 w-full" onSubmit={handleSubmit}>
<div className="relative bg-slate-300 h-64 w-full rounded-2xl mb-20 shadow-inner">
Expand Down
15 changes: 13 additions & 2 deletions inertia/pages/users/show.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useState } from 'react'
import FeedController from '#controllers/feed_controller'
import HeadOG from '@/components/generic/head_og'
import FeedList from '@/components/posts/feed_list'
import { Card, CardContent } from '@/components/ui/card'
import { InferPageProps } from '@adonisjs/inertia/types'
import { lightFormat } from 'date-fns'
import { Head } from '@inertiajs/react'
import { BadgeCheck, CalendarHeart, FilePen } from 'lucide-react'
import { CreatePost } from '@/components/posts/create'
import { UserResponse } from '#interfaces/user'
Expand Down Expand Up @@ -68,7 +68,18 @@ export default function Show({ user, posts, profile }: InferPageProps<FeedContro
if (!posts || !profile) return <>Loading..</>
return (
<>
<Head title={`@${profile.username}`} />
<HeadOG
title={`@${profile.username}`}
description={`Discover ${profile.username} on Social Adonis.`}
image={profile.attachments.avatar?.link}
url={
route('users.show', {
params: {
id: profile.id,
},
}).path
}
/>
<div className="relative min-h-[280px] lg:min-h-max w-full mb-16 lg:mb-0">
<div className="relative bg-slate-300 border border-gray-200 h-52 w-full rounded-2xl mb-4 shadow-inner">
<div className="w-full h-full rounded-2xl overflow-hidden">
Expand Down
Binary file added public/assets/images/thumbnail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 7 additions & 2 deletions start/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ router
.group(() => {
router.on('/').renderInertia('home').as('home.show')
router.get('/feed', [FeedController, 'index']).as('feed.show')
router
.group(() => {
router.get(':id', [FeedController, 'show']).as('users.show')
})
.prefix('users')
})
.use(middleware.guest())

Expand Down Expand Up @@ -66,13 +71,13 @@ router
router
.group(() => {
router.get('/', [UsersController, 'index']).as('users.index')
router.get(':id', [FeedController, 'show']).as('users.show') // TODO: Make public, and contextualize `ctx.auth.authenticate` via middleware.
router.get(':id/settings', [UsersController, 'show']).as('settings.show')
router.patch(':id', [UsersController, 'update']).as('users.update')
router.delete(':id', [UsersController, 'destroy']).as('users.destroy')
})
.prefix('users')

router.get('settings', [UsersController, 'show']).as('settings.show')

router
.group(() => {
router.post('/', [PostsController, 'store']).as('posts.store')
Expand Down
4 changes: 2 additions & 2 deletions tests/browser/admin_post_report.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { UserFactory } from '#database/factories/user_factory'
import { PostReportReason, PostReportStatus } from '#enums/post'
import testUtils from '@adonisjs/core/services/test_utils'
import { route } from '@izzyjs/route/client'
import { test } from '@japa/runner'

test.group('Admin post report', (group) => {
// FIX-ME: Izzy
const url = '/admin/posts/reports'
const url = route('admin_posts_reports.index').path

group.each.setup(() => testUtils.db().truncate())

Expand Down
39 changes: 32 additions & 7 deletions tests/browser/pages/feed.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { UserFactory } from '#database/factories/user_factory'
import testUtils from '@adonisjs/core/services/test_utils'
import { route } from '@izzyjs/route/client'
import { test } from '@japa/runner'

test.group('Acessing feed', (group) => {
group.each.setup(() => testUtils.db().truncate())

test('Fails to access the feed without being authenticated', async ({ visit }) => {
const page = await visit('/feed')
const page = await visit(route('feed.show').path)
await page.assertTextContains('body', 'Sign in')
})

test('Successfully acesses the feed while authenticated', async ({ visit, browserContext }) => {
const user = await UserFactory.create()
const created = await UserFactory.with('posts', 8).create()
await browserContext.loginAs(user)
const page = await visit('/feed')
const page = await visit(route('feed.show').path)
const locator = page.locator('.feed-list > article > .post-content')
await page.assertElementsText(
locator,
Expand All @@ -27,7 +28,7 @@ test.group('Acessing feed', (group) => {
await UserFactory.with('posts', 8).create()

await browserContext.loginAs(user)
const page = await visit('/feed')
const page = await visit(route('feed.show').path)
await page.locator('button.create-post').click()

const postContent = 'Lets get dat bread! 🍞'
Expand All @@ -42,7 +43,13 @@ test.group('Acessing feed', (group) => {
await UserFactory.with('posts', 8).create()

await browserContext.loginAs(user)
const page = await visit(`/posts/${user.posts[0].id}`)
const page = await visit(
route('posts.show', {
params: {
id: user.posts[0].id,
},
}).path
)

await page.locator('button.trigger-user-post-actions').click()
const updateButton = page.locator('button.update-post-trigger')
Expand All @@ -59,7 +66,13 @@ test.group('Acessing feed', (group) => {
await UserFactory.with('posts', 8).create()

await browserContext.loginAs(user)
const page = await visit(`/posts/${user.posts[0].id}`)
const page = await visit(
route('posts.show', {
params: {
id: user.posts[0].id,
},
}).path
)

await page.locator('button.trigger-user-post-actions').click()
const deleteButton = page.locator('button.delete-post-trigger')
Expand All @@ -75,7 +88,13 @@ test.group('Acessing feed', (group) => {
const user = await UserFactory.with('posts', 1).create()
const otherUser = await UserFactory.with('posts', 8).create()
await browserContext.loginAs(user)
const page = await visit(`/posts/${otherUser.posts[0].id}`)
const page = await visit(
route('posts.show', {
params: {
id: otherUser.posts[0].id,
},
}).path
)
await page.locator('button.trigger-user-post-actions').click()
const updateAction = page.locator('button.update-post-trigger')
const deleteAction = page.locator('button.delete-post-trigger')
Expand All @@ -88,7 +107,13 @@ test.group('Acessing feed', (group) => {
const otherUser = await UserFactory.with('posts', 8).create()

await browserContext.loginAs(user)
const page = await visit(`/posts/${otherUser.posts[0].id}`)
const page = await visit(
route('posts.show', {
params: {
id: otherUser.posts[0].id,
},
}).path
)

const reactButton = page.locator('button.trigger-user-post-react')
await reactButton.hover()
Expand Down
Loading

0 comments on commit 4af0381

Please sign in to comment.