Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .env.local.example

This file was deleted.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added .vs/MyFirstBlogFrontEnd/v17/.wsuo
Binary file not shown.
12 changes: 12 additions & 0 deletions .vs/MyFirstBlogFrontEnd/v17/DocumentLayout.backup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Version": 1,
"WorkspaceRootPath": "M:\\MyFirstBlogFrontEnd\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}
12 changes: 12 additions & 0 deletions .vs/MyFirstBlogFrontEnd/v17/DocumentLayout.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Version": 1,
"WorkspaceRootPath": "M:\\MyFirstBlogFrontEnd\\",
"Documents": [],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": []
}
]
}
4 changes: 4 additions & 0 deletions .vs/VSWorkspaceState.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"ExpandedNodes": [],
"PreviewInSolutionExplorer": false
}
Binary file added .vs/slnx.sqlite
Binary file not shown.
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}
7 changes: 6 additions & 1 deletion src/api/axiosConfig.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@

import axios from "axios"
import { isHyperlink } from '@/lib/isHyperlink'

const BASE_URL = process.env.DOTNET_SERVER_URL


const AXIOS_BASE = axios.create({
baseURL: BASE_URL,
})
})



const JSON_CLIENT = isHyperlink(BASE_URL) ? AXIOS_BASE : false

export default JSON_CLIENT

27 changes: 26 additions & 1 deletion src/api/postsApi.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import API from './axiosConfig'
/*import API from './axiosConfig'

export const getPosts = () => {
try {
Expand All @@ -12,6 +12,7 @@ export const getPosts = () => {
}

export const getPost = (postSlug) => {
console.log("Calling:", `${process.env.NEXT_PUBLIC_API_URL}/posts/${postSlug}`);
try {
return API.get(`/posts/${postSlug}`)
.then((res) => res.data)
Expand All @@ -21,3 +22,27 @@ export const getPost = (postSlug) => {
return {}
}
}
*/

import API from './axiosConfig'

export const getPosts = async () => {
try {
const res = await API.get('/posts/')
return res.data
} catch (e) {
console.error('Error fetching posts:', e)
return []
}
}

export const getPost = async (postSlug) => {
console.log("Calling:", `${process.env.NEXT_PUBLIC_API_URL}/posts/${postSlug}`);
try {
const res = await API.get(`/posts/${postSlug}`)
return res.data
} catch (e) {
console.error('Error fetching post:', e)
return {}
}
}
31 changes: 18 additions & 13 deletions src/pages/posts/[slug].jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,41 @@ import { getPost, getPosts } from "@/api/postsApi"
import { postParameters } from "@/lib/postUtilities"

export async function getStaticPaths() {
const posts = await getPosts()

const postParams = posts ? postParameters(posts) : []
const posts = await getPosts();
const postParams = posts ? postParameters(posts) : [];

return {
paths: postParams,
fallback: false,
}
fallback: 'blocking',
};
}

export async function getStaticProps(context) {
const currentPost = await getPost(context.params.slug)
const currentPost = await getPost(context.params.slug);

return {
props: { post: currentPost || {} },
if (!currentPost || !currentPost.slug) {
return { notFound: true };
}

return {
props: { post: currentPost },
};
}

export default function Post({ post }) {

const meta = {
author: 'Spencer Sharp',
author: post.author || 'Admin',
date: post.createdDate,
title: post.title,
description: post.body,
}
};

return (
<ArticleLayout meta={meta}>
{post.body}
<div className="prose">
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
</ArticleLayout>
)
);
}
92 changes: 92 additions & 0 deletions src/pages/posts/new.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useState } from 'react';
import { useRouter } from 'next/router';

export default function NewPost() {
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [errors, setErrors] = useState([]);
const router = useRouter();

const handleSubmit = async (e) => {
e.preventDefault();
const newErrors = [];

// Client-side validation
if (!title.trim()) {
newErrors.push('Title cannot be blank');
}

if (!description.trim()) {
newErrors.push('You cannot send a message with empty description');
}

if (newErrors.length > 0) {
setErrors(newErrors);
return;
}

try {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/posts`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ title, description }),
});

const data = await res.json();

if (res.status === 201) {
const slug = data?.post?.slug || title.toLowerCase().replace(/\s+/g, '-');
router.push(`/posts/${slug}`);
} else {
setErrors(data.errors || ['Something went wrong']);
}
} catch (err) {
console.error(err);
setErrors(['Server error. Please try again later.']);
}
};

return (
<div className="max-w-xl mx-auto mt-10">
<h1 className="text-2xl font-bold mb-4">Create New Post</h1>

{errors.length > 0 && (
<div className="bg-red-100 text-red-700 p-2 mb-4 rounded">
{errors.map((err, i) => (
<p key={i}>{err}</p>
))}
</div>
)}

<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block font-semibold">Title</label>
<input
type="text"
className="w-full p-2 border rounded"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
</div>

<div>
<label className="block font-semibold">Description</label>
<textarea
className="w-full p-2 border rounded"
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
</div>

<button
type="submit"
className="bg-blue-600 text-white px-4 py-2 rounded"
>
Create Post
</button>
</form>
</div>
);
}