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: 8 additions & 0 deletions .env.local.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DOTNET_SERVER_URL=http://localhost:5000
NEXT_PUBLIC_SITE_URL=http://localhost:3000
AUTH0_BASE_URL=http://localhost:3000
AUTH0_SECRET=9156f409cf1303dea93a850db47a57ed451cc530d4fc1624d0042020eae1e04c

AUTH0_ISSUER_BASE_URL=https://dev-mlmx8o81f2xj65x8.us.auth0.com
AUTH0_CLIENT_ID=ew7bYJUnrO9bEqMD3u16RDXkYakgTNw4
AUTH0_CLIENT_SECRET=mWaYEBMQ526KzRMDgl3s1GEgFC6JUD8Hyq6ookSkwLLWl47z5pobIecqY2ZAey3c
34 changes: 26 additions & 8 deletions src/api/axiosConfig.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import axios from "axios"
import { isHyperlink } from '@/lib/isHyperlink'
import axios from 'axios';

const BASE_URL = process.env.DOTNET_SERVER_URL
const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_BASE_URL || 'http://localhost:5000/api',
headers: {
'Content-Type': 'application/json',
},
timeout: 10000, // Add a timeout to handle long requests
});

const AXIOS_BASE = axios.create({
baseURL: BASE_URL,
})
axiosInstance.interceptors.request.use(
(config) => {
// You can add additional logic here, e.g., attaching tokens
return config;
},
(error) => {
return Promise.reject(error);
}
);

const JSON_CLIENT = isHyperlink(BASE_URL) ? AXIOS_BASE : false
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
// You can handle global errors here
return Promise.reject(error);
}
);

export default axiosInstance;

export default JSON_CLIENT
2 changes: 1 addition & 1 deletion src/api/postsApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ export const getPost = (postSlug) => {
console.error(e)
return {}
}
}
}
134 changes: 64 additions & 70 deletions src/components/Card.jsx
Original file line number Diff line number Diff line change
@@ -1,94 +1,88 @@
import Link from 'next/link'
import clsx from 'clsx'
import Link from 'next/link';
import clsx from 'clsx';
import { formatDate } from '../lib/formatDate';

function ChevronRightIcon(props) {
return (
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" {...props}>
<path
d="M6.75 5.75 9.25 8l-2.5 2.25"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
// ChevronRightIcon Component
const ChevronRightIcon = ({ className, ...props }) => (
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" className={className} {...props}>
<path
d="M6.75 5.75 9.25 8l-2.5 2.25"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);

export function Card({ as: Component = 'div', className, children }) {
return (
<Component
className={clsx(className, 'group relative flex flex-col items-start')}
>
{children}
</Component>
)
}
// Card Component
export const Card = ({ as: Component = 'div', className, children }) => (
<Component className={clsx('group relative flex flex-col items-start', className)}>
{children}
</Component>
);

Card.Link = function CardLink({ children, ...props }) {
return (
<>
<div className="absolute -inset-y-6 -inset-x-4 z-0 scale-95 bg-zinc-50 opacity-0 transition group-hover:scale-100 group-hover:opacity-100 sm:-inset-x-6 sm:rounded-2xl" />
<Link {...props}>
<span className="absolute -inset-y-6 -inset-x-4 z-20 sm:-inset-x-6 sm:rounded-2xl" />
<span className="relative z-10">{children}</span>
</Link>
</>
)
}
// CardLink Component
export const CardLink = ({ children, ...props }) => (
<>
<div className="absolute -inset-y-6 -inset-x-4 z-0 scale-95 bg-zinc-50 opacity-0 transition group-hover:scale-100 group-hover:opacity-100 sm:-inset-x-6 sm:rounded-2xl" />
<Link {...props}>
<span className="absolute -inset-y-6 -inset-x-4 z-20 sm:-inset-x-6 sm:rounded-2xl" />
<span className="relative z-10">{children}</span>
</Link>
</>
);

Card.Title = function CardTitle({ as: Component = 'h2', href, children }) {
return (
<Component className="text-base font-semibold tracking-tight text-zinc-800">
{href ? <Card.Link href={href}>{children}</Card.Link> : children}
</Component>
)
}
// CardTitle Component
export const CardTitle = ({ as: Component = 'h2', href, children }) => (
<Component className="text-base font-semibold tracking-tight text-zinc-800">
{href ? <CardLink href={href}>{children}</CardLink> : children}
</Component>
);

Card.Description = function CardDescription({ children }) {
return (
<p className="relative z-10 mt-2 text-sm text-zinc-600">
{children}
</p>
)
}
// CardDescription Component
export const CardDescription = ({ children }) => (
<p className="relative z-10 mt-2 text-sm text-zinc-600">
{children}
</p>
);

Card.Cta = function CardCta({ children }) {
return (
<div
aria-hidden="true"
className="relative z-10 mt-4 flex items-center text-sm font-medium text-teal-500"
>
{children}
<ChevronRightIcon className="ml-1 h-4 w-4 stroke-current" />
</div>
)
}
// CardCta Component
export const CardCta = ({ children }) => (
<div
aria-hidden="true"
className="relative z-10 mt-4 flex items-center text-sm font-medium text-teal-500"
>
{children}
<ChevronRightIcon className="ml-1 h-4 w-4 stroke-current" />
</div>
);

Card.Eyebrow = function CardEyebrow({
// CardEyebrow Component
export const CardEyebrow = ({
as: Component = 'p',
decorate = false,
className,
children,
dateTime,
...props
}) {
}) => {
const content = dateTime ? formatDate(dateTime) : children;

return (
<Component
className={clsx(
className,
'relative z-10 order-first mb-3 flex items-center text-sm text-zinc-400',
decorate && 'pl-3.5'
decorate && 'pl-3.5',
className
)}
{...props}
>
{decorate && (
<span
className="absolute inset-y-0 left-0 flex items-center"
aria-hidden="true"
>
<span className="absolute inset-y-0 left-0 flex items-center" aria-hidden="true">
<span className="h-4 w-0.5 rounded-full bg-zinc-200" />
</span>
)}
{children}
{content}
</Component>
)
}
);
};
102 changes: 102 additions & 0 deletions src/components/CreatePostForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { useState } from 'react';
import { createPost } from '../api/postsApi';
import { formatDate } from '../lib/formatDate';

const CreatePostForm = () => {
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [body, setBody] = useState('');
const [createdDate, setCreatedDate] = useState(new Date());
const [errors, setErrors] = useState([]); // State to manage errors

const handleSubmit = async (e) => {
e.preventDefault();
setErrors([]); // Clear previous errors

try {
const newPost = {
title,
description,
body,
createdDate: formatDate(createdDate.toISOString()) // Format the date before submission
};

const response = await createPost(newPost);

if (response.status === 201) {
console.log('Post created successfully:', response.data);
// Reset the form after successful submission
setTitle('');
setDescription('');
setBody('');
setCreatedDate(new Date()); // Reset to current date/time
} else {
console.error('Unexpected response:', response);
setErrors(['Unexpected response from the server.']);
}
} catch (error) {
console.error('Error creating post:', error);

if (error.response) {
console.error('Server Error:', error.response.data);
setErrors(error.response.data.errors || ['An error occurred while creating the post.']);
} else if (error.request) {
console.error('Network Error:', error.request);
setErrors(['Network error: Please check your internet connection.']);
} else {
console.error('Error:', error.message);
setErrors([error.message]);
}
}
};

return (
<form onSubmit={handleSubmit}>
<div>
<label>Title:</label>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
</div>
<div>
<label>Description:</label>
<input
type="text"
value={description}
onChange={(e) => setDescription(e.target.value)}
required
/>
</div>
<div>
<label>Body:</label>
<textarea
value={body}
onChange={(e) => setBody(e.target.value)}
required
/>
</div>
<div>
<label>Created Date:</label>
<input
type="datetime-local"
value={createdDate.toISOString().slice(0, 16)} // Format the date input field
onChange={(e) => setCreatedDate(new Date(e.target.value))}
required
/>
</div>
<button type="submit">Create Post</button>
{errors.length > 0 && (
<ul style={{ color: 'red' }}>
{errors.map((error, index) => (
<li key={index}>{error}</li>
))}
</ul>
)}
</form>
);
};

export default CreatePostForm;
Loading