Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
louderthan10 committed Nov 21, 2024
2 parents 2df119e + 633b15d commit 8af15c5
Show file tree
Hide file tree
Showing 15 changed files with 299 additions and 102 deletions.
3 changes: 2 additions & 1 deletion backend/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
},
"autoload": {
"psr-4": {
"modules\\": "modules/"
"modules\\": "modules/",
"backend\\": "."
}
},
"config": {
Expand Down
4 changes: 4 additions & 0 deletions backend/config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@

return [
'id' => App::env('CRAFT_APP_ID') ?: 'CraftCMS',
'modules' => [
'authorinfo' => modules\authorinfo\Module::class,
],
'bootstrap' => ['authorinfo'],
];
100 changes: 100 additions & 0 deletions backend/modules/authorinfo/Module.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php
namespace modules\authorinfo;

use Craft;
use craft\elements\User;
use craft\events\DefineGqlTypeFieldsEvent;
use craft\gql\TypeManager;
use GraphQL\Type\Definition\Type;
use yii\base\Event;

class Module extends \yii\base\Module
{
public static $instance;

/**
* Cache for the admin user to avoid multiple queries
*/
private ?User $adminUser = null;

public function init()
{
parent::init();
self::$instance = $this;

Event::on(
TypeManager::class,
TypeManager::EVENT_DEFINE_GQL_TYPE_FIELDS,
[$this, 'handleDefineGqlTypeFields']
);
}

/**
* Get the admin user, caching the result
*/
private function getAdminUser(): ?User
{
if ($this->adminUser === null) {
$this->adminUser = User::find()
->admin(true)
->status(null)
->orderBy(['elements.id' => SORT_ASC])
->one();

if ($this->adminUser) {
Craft::info(
"Found admin user: ID: {$this->adminUser->id}, Name: {$this->adminUser->fullName}",
__METHOD__
);
} else {
Craft::warning('No admin user found', __METHOD__);
}
}

return $this->adminUser;
}

/**
* Handle the DefineGqlTypeFields event
*/
public function handleDefineGqlTypeFields(DefineGqlTypeFieldsEvent $event): void
{
if ($event->typeName !== 'EntryInterface') {
return;
}

$event->fields['authorId'] = [
'name' => 'authorId',
'type' => Type::int(),
'description' => 'The entry author\'s ID',
'resolve' => function($source) {
try {
if ($source->getSection()->type === 'single') {
return $this->getAdminUser()?->id;
}
return $source->authorId;
} catch (\Throwable $e) {
Craft::error("Error resolving authorId: {$e->getMessage()}", __METHOD__);
return null;
}
}
];

$event->fields['authorName'] = [
'name' => 'authorName',
'type' => Type::string(),
'description' => 'The entry author\'s name',
'resolve' => function($source) {
try {
if ($source->getSection()->type === 'single') {
return $this->getAdminUser()?->fullName;
}
return $source->getAuthor()?->fullName;
} catch (\Throwable $e) {
Craft::error("Error resolving authorName: {$e->getMessage()}", __METHOD__);
return null;
}
}
];
}
}
1 change: 0 additions & 1 deletion frontend/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const graphql = useGraphQL()
const { data: globalsData } = await useAsyncData('globals', async () => {
try {
const result = await graphql.query(GLOBALS_QUERY)
console.log('GraphQL result:', result) // Debug log
return {
global: result?.globalEntries?.[0] || {},
pages: result?.pagesEntries || []
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/alert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<div
v-if="flashes.length > 0"
role="alert"
class="sticky top-0 left-0 right-0 z-50"
class="absolute top-0 left-0 right-0 z-50"
>
<p
v-for="flash in flashes"
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/navigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ defineProps({
</li>
<li v-for="page in pages" :key="page.id">
<NuxtLink
:to="page.uri"
:to="`/${page.uri}`"
class="block p-2 hover:underline text-red-600 hover:text-red-600"
active-class="text-red-600"
:aria-current="$route.path === page.uri ? 'page' : null"
:aria-current="$route.path === `/${page.uri}` ? 'page' : null"
>
{{ page.title }}
</NuxtLink>
Expand Down
24 changes: 19 additions & 5 deletions frontend/components/postForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const config = useRuntimeConfig()
const graphql = useGraphQL()
const { addFlash } = useFlashes()
const message = ref('')
const authorId = ref(config.public.ADMIN_USER_ID)
const loading = ref(false)
const emit = defineEmits(['post-submitted'])
Expand All @@ -18,6 +17,13 @@ const generateTitle = (text) => {
return `Post: ${words}${words ? '...' : ''}`
}
const props = defineProps({
authorId: {
type: Number,
required: true
}
})
const title = computed(() => generateTitle(message.value))
const submitPost = async () => {
Expand All @@ -27,24 +33,32 @@ const submitPost = async () => {
}
loading.value = true
try {
console.log('Submitting with:', {
title: title.value,
message: message.value,
authorId: props.authorId
})
const result = await graphql.query(CREATE_POST_MUTATION, {
title: title.value,
message: message.value,
authorId: authorId.value
authorId: props.authorId.toString()
}, {
private: true
})
if (!result?.save_posts_text_Entry) {
console.log('Mutation result:', result)
if (!result?.save_guestbookPosts_text_Entry) {
throw new Error('No data returned from the mutation')
}
addFlash('Message posted successfully', 'success')
message.value = ''
emit('post-submitted')
} catch (err) {
addFlash('Error posting message', 'error')
console.error('Error creating post:', err.message)
addFlash(`Error posting message: ${err.message}`, 'error')
console.error('Error creating post:', err)
} finally {
loading.value = false
}
Expand Down
77 changes: 77 additions & 0 deletions frontend/components/postList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<script setup>
import { useGraphQL } from '@/composables/useGraphQL'
import { usePaginatedData } from '@/composables/usePaginatedData'
import { GUESTBOOK_POSTS_QUERY } from '@/queries/guestbookPosts.mjs'
const props = defineProps({
previewToken: {
type: String,
default: null
}
})
const fetchPosts = async (page, perPage) => {
try {
const result = await useGraphQL().query(GUESTBOOK_POSTS_QUERY, {
limit: perPage,
offset: (page - 1) * perPage
}, {
previewToken: props.previewToken
})
return {
posts: result?.guestbookPostsEntries || [],
total: result?.entryCount || 0
}
} catch (err) {
console.error('GraphQL Error:', err)
throw err
}
}
const {
currentPage,
data,
totalPages,
error,
loading,
updateCurrentPage,
refresh
} = usePaginatedData(fetchPosts)
defineExpose({
refresh
})
</script>
<template>
<div v-if="loading" class="py-4">
Loading...
</div>
<div v-else-if="error" class="py-4 text-red-600">
{{ error.message }}
</div>
<div v-else>
<div v-if="data?.posts?.length > 0">
<ol class="mb-2 divide-y divide-slate-300">
<li v-for="post in data.posts" :key="post.id">
<article class="text-xl py-6">
<div v-html="post.textBlock"></div>
<p class="text-sm mt-1">
<time :datetime="post.postDate">{{ post.postDate }}</time>
</p>
</article>
</li>
</ol>
<Pagination
v-if="totalPages > 1"
:currentPage="currentPage"
:totalPages="totalPages"
@update:currentPage="updateCurrentPage"
/>
</div>
<p v-else class="text-2xl">No entries yet. Create one using the form.</p>
</div>
</template>
16 changes: 15 additions & 1 deletion frontend/composables/usePaginatedData.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ export function usePaginatedData(fetchData, initialItemsPerPage = 3) {
}
}

const refresh = async () => {
loading.value = true
try {
const newData = await fetchData(currentPage.value, itemsPerPage.value)
data.value = newData
} catch (err) {
error.value = err
console.error('Error refreshing data:', err)
} finally {
loading.value = false
}
}

watch(() => route.query.page, async (newPage) => {
const page = parseInt(newPage) || 1
if (page !== currentPage.value) {
Expand All @@ -57,6 +70,7 @@ export function usePaginatedData(fetchData, initialItemsPerPage = 3) {
loading,
error,
updateCurrentPage,
fetchPageData
fetchPageData,
refresh
}
}
3 changes: 1 addition & 2 deletions frontend/nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ export default defineNuxtConfig({
AUTH_HEADER: process.env.AUTH_HEADER,
CRAFT_URL: process.env.CRAFT_URL,
BASE_URL: process.env.BASE_URL,
SITE_NAME: process.env.SITE_NAME,
ADMIN_USER_ID: process.env.ADMIN_USER_ID
SITE_NAME: process.env.SITE_NAME
}
},
vite: {
Expand Down
3 changes: 3 additions & 0 deletions frontend/pages/blog/[slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ useHead(() => ({
<time v-if="currentPost.postDate" :datetime="currentPost.postDate">
{{ currentPost.postDate }}
</time>
<span v-if="currentPost.authorName" class="block">
By {{ currentPost.authorName }}
</span>
</p>
</div>
</div>
Expand Down
Loading

0 comments on commit 8af15c5

Please sign in to comment.