diff --git a/.eslintrc.js b/.eslintrc.js
index 0290d4b8..642ed9cf 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -2,9 +2,14 @@ var tsConfigs = ['./tsconfig.json'];
var tsConfigEmail = ['./tsconfig-emails.json'];
var srcRuleOverrides = {
- 'prettier/prettier': 1,
- '@typescript-eslint/no-unused-vars': 1,
- '@typescript-eslint/no-non-null-assertion': 'error',
+ 'prettier/prettier': 0,
+ '@typescript-eslint/no-unused-vars': 0,
+ '@typescript-eslint/no-unused-expressions': 0,
+ '@typescript-eslint/no-non-null-assertion': 0,
+ '@next/next/no-img-element': 0,
+ '@typescript-eslint/no-empty-object-type': 0,
+ '@typescript-eslint/no-explicit-any': 0,
+ '@typescript-eslint/ban-ts-comment': 0,
};
module.exports = {
diff --git a/next-env.d.ts b/next-env.d.ts
index 725dd6f2..fd36f949 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -3,4 +3,4 @@
///
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
+// see https://nextjs.org/docs/basic-features/typescript for more information.
diff --git a/src/app/(external-pages)/blog/(list)/page.tsx b/src/app/(external-pages)/blog/(list)/page.tsx
deleted file mode 100644
index c7de6294..00000000
--- a/src/app/(external-pages)/blog/(list)/page.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { T } from '@/components/ui/Typography';
-import {
- anonGetAllBlogTags,
- anonGetPublishedBlogPosts,
-} from '@/data/anon/internalBlog';
-import { Suspense } from 'react';
-import { PublicBlogList } from '../PublicBlogList';
-import { TagsNav } from '../TagsNav';
-
-export const metadata = {
- title: 'Blog List | Nextbase',
- description: 'Collection of the latest blog posts from the team at Nextbase',
-};
-
-async function Tags() {
- const tags = await anonGetAllBlogTags();
- return ;
-}
-
-async function BlogList() {
- const blogPosts = await anonGetPublishedBlogPosts();
- return ;
-}
-
-export default async function BlogListPage() {
- return (
-
-
-
- Blog
- All blog posts
-
- Here is a collection of the latest blog posts from the team at
- Nextbase.
-
-
-
Loading tags...}>
-
-
-
-
Loading posts...}>
-
-
-
- );
-}
diff --git a/src/app/(external-pages)/blog/AuthorCard.tsx b/src/app/(external-pages)/blog/AuthorCard.tsx
deleted file mode 100644
index 7faea06d..00000000
--- a/src/app/(external-pages)/blog/AuthorCard.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
-import {
- Card,
- CardDescription,
- CardHeader,
- CardTitle,
-} from '@/components/ui/card';
-import Link from 'next/link';
-
-type Props = {
- author: {
- avatar_url: string;
- bio: string;
- created_at: string;
- display_name: string;
- facebook_handle: string | null;
- instagram_handle: string | null;
- linkedin_handle: string | null;
- twitter_handle: string | null;
- updated_at: string;
- user_id: string;
- website_url: string | null;
- };
-};
-
-const AuthorCard = ({ author }: Props) => {
- return (
-
-
-
-
-
-
-
- {generateInitials(author.display_name)}
-
-
-
- {author.display_name}
-
- {author.bio.length > 120
- ? author.bio.slice(0, 120) + '...'
- : author.bio.length}
-
-
-
-
-
-
- );
-};
-
-export default AuthorCard;
-
-function generateInitials(name: string) {
- // Split the name into individual words
- const words = name.split(' ');
-
- // Initialize an empty string to store initials
- let initials = '';
-
- // Iterate through each word
- for (let i = 0; i < words.length; i++) {
- // Get the first character of each word and convert it to uppercase
- initials += words[i][0].toUpperCase();
- }
-
- // Return the generated initials
- return initials;
-}
diff --git a/src/app/(external-pages)/blog/MobileNavigation.tsx b/src/app/(external-pages)/blog/MobileNavigation.tsx
deleted file mode 100644
index f1c79d8f..00000000
--- a/src/app/(external-pages)/blog/MobileNavigation.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-'use client';
-import { Dialog } from '@headlessui/react';
-import Link from 'next/link';
-import { useRouter } from 'next/navigation';
-import { ComponentProps, useState } from 'react';
-
-function MenuIcon(props: ComponentProps<'svg'>) {
- return (
-
- );
-}
-
-function CloseIcon(props: ComponentProps<'svg'>) {
- return (
-
- );
-}
-
-export function MobileNavigation() {
- const router = useRouter();
- const [isOpen, setIsOpen] = useState(false);
-
- // useEffect(() => {
- // if (!isOpen) return
-
- // function onRouteChange() {
- // setIsOpen(false)
- // }
-
- // router.events.on('routeChangeComplete', onRouteChange)
- // router.events.on('routeChangeError', onRouteChange)
-
- // return () => {
- // router.events.off('routeChangeComplete', onRouteChange)
- // router.events.off('routeChangeError', onRouteChange)
- // }
- // }, [router, isOpen])
-
- return (
- <>
-
-
- >
- );
-}
diff --git a/src/app/(external-pages)/blog/Navbar.tsx b/src/app/(external-pages)/blog/Navbar.tsx
deleted file mode 100644
index 6e35efa3..00000000
--- a/src/app/(external-pages)/blog/Navbar.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-'use client';
-import { cn } from '@/utils/cn';
-import Link from 'next/link';
-import { usePathname } from 'next/navigation';
-import { ComponentPropsWithRef, useEffect, useState } from 'react';
-import { MobileNavigation } from './MobileNavigation';
-
-function NavLink({ href, ...props }: ComponentPropsWithRef) {
- const pathname = usePathname();
- const isActive = pathname === href;
- return (
-
- );
-}
-
-export function Navbar() {
- const [isScrolled, setIsScrolled] = useState(false);
-
- useEffect(() => {
- function onScroll() {
- setIsScrolled(window.scrollY > 0);
- }
- onScroll();
- window.addEventListener('scroll', onScroll, { passive: true });
- return () => {
- window.removeEventListener('scroll', onScroll);
- };
- }, []);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Blog
-
-
- Docs
-
-
- Changelog
-
-
- Roadmap
-
-
-
-
-
-
- );
-}
diff --git a/src/app/(external-pages)/blog/PublicBlogList.tsx b/src/app/(external-pages)/blog/PublicBlogList.tsx
deleted file mode 100644
index 036fb3d4..00000000
--- a/src/app/(external-pages)/blog/PublicBlogList.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { T } from '@/components/ui/Typography';
-import { Table } from '@/types';
-import moment from 'moment';
-
-export function PublicBlogList({
- blogPosts,
-}: {
- blogPosts: Array>;
-}) {
- return (
- <>
- {blogPosts.length ? (
-
-
- {blogPosts.map((post) => (
-
-
-
-
-
-
-
-
-
-
-
- ))}
-
-
- ) : (
- No blog posts yet.
- )}
- >
- );
-}
diff --git a/src/app/(external-pages)/blog/TagsNav.tsx b/src/app/(external-pages)/blog/TagsNav.tsx
deleted file mode 100644
index 2923d494..00000000
--- a/src/app/(external-pages)/blog/TagsNav.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import { Button } from '@/components/ui/button';
-import { Table } from '@/types';
-import Link from 'next/link';
-
-export function TagsNav({
- tags,
-}: {
- tags: Table<'internal_blog_post_tags'>[];
-}) {
- return (
-
-
-
-
-
- {tags.map((tag) => (
-
-
-
- ))}
-
- );
-}
diff --git a/src/app/(external-pages)/blog/[slug]/BlogContent.tsx b/src/app/(external-pages)/blog/[slug]/BlogContent.tsx
deleted file mode 100644
index 200e44d0..00000000
--- a/src/app/(external-pages)/blog/[slug]/BlogContent.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-'use client';
-
-import { getTipTapExtention } from '@/components/tip-tap-Editor/extensions';
-import type { Table } from '@/types';
-import { generateHTML } from '@tiptap/core';
-
-export function BlogContent({
- jsonContent,
-}: {
- jsonContent: Table<'internal_blog_posts'>['json_content'];
-}) {
- const validContent =
- typeof jsonContent === 'string'
- ? JSON.parse(jsonContent)
- : typeof jsonContent === 'object' && jsonContent !== null
- ? jsonContent
- : {};
- return (
-
- );
-}
diff --git a/src/app/(external-pages)/blog/[slug]/BlogContentWrapper.tsx b/src/app/(external-pages)/blog/[slug]/BlogContentWrapper.tsx
deleted file mode 100644
index e183c041..00000000
--- a/src/app/(external-pages)/blog/[slug]/BlogContentWrapper.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-'use client';
-
-import { Skeleton } from '@/components/ui/skeleton';
-import { Table } from '@/types';
-import dynamic from 'next/dynamic';
-import { Suspense } from 'react';
-
-const BlogContent = dynamic(
- () => import('./BlogContent').then((m) => m.BlogContent),
- { ssr: false },
-);
-
-export function BlogContentWrapper({
- jsonContent,
-}: {
- jsonContent: Table<'internal_blog_posts'>['json_content'];
-}) {
- return (
- }>
-
-
- );
-}
diff --git a/src/app/(external-pages)/blog/[slug]/page.tsx b/src/app/(external-pages)/blog/[slug]/page.tsx
deleted file mode 100644
index c22cfb7f..00000000
--- a/src/app/(external-pages)/blog/[slug]/page.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import {
- anonGetPublishedBlogPostBySlug,
- anonGetPublishedBlogPosts,
-} from "@/data/anon/internalBlog";
-
-import { T } from "@/components/ui/Typography";
-import type { Metadata } from "next";
-import { notFound } from "next/navigation";
-import { z } from "zod";
-import AuthorCard from "../AuthorCard";
-import { BlogContentWrapper } from "./BlogContentWrapper";
-
-const paramsSchema = z.object({
- slug: z.string(),
-});
-
-// Return a list of `params` to populate the [slug] dynamic segment
-export async function generateStaticParams() {
- const posts = await anonGetPublishedBlogPosts();
-
- return posts.map((post) => ({
- slug: post.slug,
- }));
-}
-
-export async function generateMetadata({
- params,
-}: {
- params: unknown;
-}): Promise {
- // read route params
- const { slug } = paramsSchema.parse(params);
- const post = await anonGetPublishedBlogPostBySlug(slug);
-
- console.log(post)
-
- return {
- title: `${post.title} | Blog | Nextbase Boilerplate`,
- description: post.summary,
- openGraph: {
- title: `${post.title} | Blog | Nextbase Boilerplate`,
- description: post.summary,
- type: "website",
- images: post.cover_image ? [post.cover_image] : undefined,
- },
- twitter: {
- images: post.cover_image ? [post.cover_image] : undefined,
- title: `${post.title} | Blog | Nextbase Boilerplate`,
- card: "summary_large_image",
- site: "@usenextbase",
- description: post.summary,
- },
- };
-}
-export default async function BlogPostPage({ params }: { params: unknown }) {
- try {
- const { slug } = paramsSchema.parse(params);
- const post = await anonGetPublishedBlogPostBySlug(slug);
-
- return (
-
- {post.cover_image ? (
-
- ) : null}
-
-
{post.title}
-
-
- {post?.internal_blog_author_posts[0]?.internal_blog_author_profiles ? (
- <>
-
Author
-
- >
- ) : null}
-
- );
- } catch (error) {
- return notFound();
- }
-}
diff --git a/src/app/(external-pages)/blog/authors/[authorId]/page.tsx b/src/app/(external-pages)/blog/authors/[authorId]/page.tsx
deleted file mode 100644
index 15ef2317..00000000
--- a/src/app/(external-pages)/blog/authors/[authorId]/page.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-import { T } from '@/components/ui/Typography';
-import {
- anonGetBlogPostsByAuthorId,
- anonGetOneAuthor,
-} from '@/data/anon/internalBlog';
-import moment from 'moment';
-import { notFound } from 'next/navigation';
-import { Suspense } from 'react';
-import { z } from 'zod';
-
-const paramsSchema = z.object({
- authorId: z.string(),
-});
-
-export default async function BlogPostPage({ params }: { params: unknown }) {
- const { authorId } = paramsSchema.parse(params);
-
- const author = await anonGetOneAuthor(authorId);
- const blogs = await anonGetBlogPostsByAuthorId(authorId);
- try {
- return (
-
-
-
- Blogs
- All {author[0].display_name}'s posts
-
- Here is a collection of the latest blog posts
-
-
-
-
-
Loading authors...}>
-
-
- {blogs.map(({ internal_blog_posts }) => (
-
-
-
-
-
-
-
-
-
-
-
- {internal_blog_posts?.summary}
-
-
-
-
- ))}
-
-
-
-
-
- );
- } catch (error) {
- return notFound();
- }
-}
diff --git a/src/app/(external-pages)/blog/authors/page.tsx b/src/app/(external-pages)/blog/authors/page.tsx
deleted file mode 100644
index 357357e6..00000000
--- a/src/app/(external-pages)/blog/authors/page.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { T } from '@/components/ui/Typography';
-import { anonGetAllAuthors } from '@/data/anon/internalBlog';
-import { notFound } from 'next/navigation';
-import { Suspense } from 'react';
-import AuthorCard from '../AuthorCard';
-
-export default async function BlogPostPage({ params }: { params: unknown }) {
- const authors = await anonGetAllAuthors();
- try {
- return (
-
-
-
- Contributions
- Authors
-
- Our blog is made possible because of contributions from these
- awesome folks!
-
-
-
-
-
Loading authors...}>
- {authors.map((author) => (
-
- ))}
-
-
-
- );
- } catch (error) {
- return notFound();
- }
-}
diff --git a/src/app/(external-pages)/blog/layout.css b/src/app/(external-pages)/blog/layout.css
deleted file mode 100644
index cc1c72cc..00000000
--- a/src/app/(external-pages)/blog/layout.css
+++ /dev/null
@@ -1,3 +0,0 @@
-html {
- scroll-behavior: smooth;
-}
diff --git a/src/app/(external-pages)/blog/layout.tsx b/src/app/(external-pages)/blog/layout.tsx
deleted file mode 100644
index af27dff1..00000000
--- a/src/app/(external-pages)/blog/layout.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import './layout.css';
-import { Navbar } from './Navbar';
-
-export default function Layout({ children }: { children: React.ReactNode }) {
- return (
-
- );
-}
diff --git a/src/app/(external-pages)/blog/tag/[tagSlug]/page.tsx b/src/app/(external-pages)/blog/tag/[tagSlug]/page.tsx
deleted file mode 100644
index c816a4be..00000000
--- a/src/app/(external-pages)/blog/tag/[tagSlug]/page.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { T } from '@/components/ui/Typography';
-import { Metadata } from 'next';
-import { z } from 'zod';
-import { PublicBlogList } from '../../PublicBlogList';
-import { TagsNav } from '../../TagsNav';
-import {
- anonGetAllBlogTags,
- anonGetPublishedBlogPosts,
- anonGetPublishedBlogPostsByTagSlug,
- anonGetTagBySlug,
-} from '@/data/anon/internalBlog';
-import { Suspense } from 'react';
-
-const BlogListByTagPageParamsSchema = z.object({
- tagSlug: z.string(),
-});
-
-export async function generateMetadata({
- params,
-}: {
- params: unknown;
-}): Promise {
- // read route params
- const { tagSlug } = BlogListByTagPageParamsSchema.parse(params);
- const tag = await anonGetTagBySlug(tagSlug);
-
- return {
- title: `${tag.name} | Blog | Nextbase Ultimate`,
- description: tag.description,
- };
-}
-
-async function Tags() {
- const tags = await anonGetAllBlogTags();
- return ;
-}
-
-async function BlogList({ tagSlug }: { tagSlug: string }) {
- const blogPosts = await anonGetPublishedBlogPostsByTagSlug(tagSlug);
- return ;
-}
-
-export default async function BlogListByTagPage({
- params,
-}: {
- params: unknown;
-}) {
- const { tagSlug } = BlogListByTagPageParamsSchema.parse(params);
-
- const tag = await anonGetTagBySlug(tagSlug);
-
- return (
-
-
-
- Blog
- {tag.name}
- {tag.description}
-
-
Loading tags...}>
-
-
-
-
Loading posts...}>
-
-
-
- );
-}
diff --git a/src/data/feedback.ts b/src/data/feedback.ts
index d2667813..213ce51a 100644
--- a/src/data/feedback.ts
+++ b/src/data/feedback.ts
@@ -8,10 +8,17 @@ import { serverGetLoggedInUser } from '@/utils/server/serverGetLoggedInUser';
import { serverGetUserType } from '@/utils/server/serverGetUserType';
import { userRoles } from '@/utils/userTypes';
import { revalidatePath } from 'next/cache';
-import { createFeedbackAddedToRoadmapUpdatedNotification, createFeedbackPriorityChangedNotification, createFeedbackReceivedCommentNotification, createFeedbackStatusChangedNotification, createFeedbackTypeUpdatedNotification, createFeedbackVisibilityUpdatedNotification, createUpdateFeedbackOpenForCommentsNotification } from './user/notifications';
+import {
+ createFeedbackAddedToRoadmapUpdatedNotification,
+ createFeedbackPriorityChangedNotification,
+ createFeedbackReceivedCommentNotification,
+ createFeedbackStatusChangedNotification,
+ createFeedbackTypeUpdatedNotification,
+ createFeedbackVisibilityUpdatedNotification,
+ createUpdateFeedbackOpenForCommentsNotification,
+} from './user/notifications';
import { getUserFullName } from './user/user';
-
export async function addCommentToInternalFeedbackThread({
feedbackId,
content,
@@ -42,7 +49,13 @@ export async function addCommentToInternalFeedbackThread({
* App admins can comment on all the feedbacks
* normal user can comment on their own feedback and the one's with open for public
*/
- if (!(feedbackThread?.open_for_public_discussion || feedbackThread?.user_id == user.id || userRoleType == userRoles.ADMIN)) {
+ if (
+ !(
+ feedbackThread?.open_for_public_discussion ||
+ feedbackThread?.user_id == user.id ||
+ userRoleType == userRoles.ADMIN
+ )
+ ) {
return {
status: 'error',
message: 'This feedback thread is not open for public discussion',
@@ -61,7 +74,7 @@ export async function addCommentToInternalFeedbackThread({
};
}
- const userFullName = await getUserFullName(user.id)
+ const userFullName = await getUserFullName(user.id);
await createFeedbackReceivedCommentNotification({
feedbackId,
@@ -69,7 +82,7 @@ export async function addCommentToInternalFeedbackThread({
comment: content,
commenterId: user.id,
commenterName: userFullName ?? 'User',
- })
+ });
revalidatePath('/feedback', 'layout');
revalidatePath(`/feedback/${feedbackId}`, 'layout');
@@ -77,7 +90,6 @@ export async function addCommentToInternalFeedbackThread({
status: 'success',
data,
};
-
} catch (error) {
return {
status: 'error',
@@ -166,7 +178,7 @@ export async function adminUpdateFeedbackStatus({
.from('internal_feedback_threads')
.select('user_id, status')
.eq('id', feedbackId)
- .single()
+ .single();
if (feedbackThreadError) {
return {
@@ -177,7 +189,7 @@ export async function adminUpdateFeedbackStatus({
const { error } = await supabaseAdminClient
.from('internal_feedback_threads')
.update({ status })
- .eq('id', feedbackId)
+ .eq('id', feedbackId);
if (error) {
return { status: 'error', message: error.message };
@@ -215,7 +227,7 @@ export async function adminUpdateFeedbackType({
.from('internal_feedback_threads')
.select('user_id, type')
.eq('id', feedbackId)
- .single()
+ .single();
if (feedbackThreadError) {
return {
@@ -266,7 +278,7 @@ export async function adminUpdateFeedbackPriority({
.from('internal_feedback_threads')
.select('user_id, priority')
.eq('id', feedbackId)
- .single()
+ .single();
if (feedbackThreadError) {
return {
@@ -331,8 +343,8 @@ export async function adminToggleFeedbackFromRoadmap({
await createFeedbackAddedToRoadmapUpdatedNotification({
feedbackId,
isInRoadmap,
- updaterId: user.id
- })
+ updaterId: user.id,
+ });
revalidatePath('/feedback', 'page');
revalidatePath(`/feedback/${feedbackId}`, 'page');
@@ -373,8 +385,8 @@ export async function adminToggleFeedbackOpenForComments({
await createUpdateFeedbackOpenForCommentsNotification({
feedbackId,
isOpenForComments,
- updaterId: user.id
- })
+ updaterId: user.id,
+ });
revalidatePath('/feedback', 'page');
revalidatePath(`/feedback/${feedbackId}`, 'page');
@@ -408,8 +420,8 @@ export async function adminToggleFeedbackVisibility({
await createFeedbackVisibilityUpdatedNotification({
feedbackId,
isPubliclyVisible,
- updaterId: user.id
- })
+ updaterId: user.id,
+ });
revalidatePath('/feedback', 'page');
revalidatePath(`/feedback/${feedbackId}`, 'page');
@@ -417,7 +429,13 @@ export async function adminToggleFeedbackVisibility({
return { status: 'success' };
}
-export async function getFeedbackStakeholdersExceptMentionedUser({ feedbackId, excludedUserId }: { feedbackId: string, excludedUserId?: string }): Promise {
+export async function getFeedbackStakeholdersExceptMentionedUser({
+ feedbackId,
+ excludedUserId,
+}: {
+ feedbackId: string;
+ excludedUserId?: string;
+}): Promise {
// return all the user ids that are concerned with the feedback conversation including owner
// except the one mentioned, the mentioned user could be owner of the feedback thread or the commentator or logged in user
try {
@@ -430,15 +448,15 @@ export async function getFeedbackStakeholdersExceptMentionedUser({ feedbackId, e
const feedbackCommentatorsQuery = supabaseClient
.from('internal_feedback_comments')
.select('user_id')
- .eq('thread_id', feedbackId)
+ .eq('thread_id', feedbackId);
- const [feedbackOwnerResult, feedbackCommentatorsResult] = await Promise.all([
- feedbackOwnerQuery,
- feedbackCommentatorsQuery
- ]);
+ const [feedbackOwnerResult, feedbackCommentatorsResult] = await Promise.all(
+ [feedbackOwnerQuery, feedbackCommentatorsQuery],
+ );
if (feedbackOwnerResult.error) throw feedbackOwnerResult.error;
- if (feedbackCommentatorsResult.error) throw feedbackCommentatorsResult.error;
+ if (feedbackCommentatorsResult.error)
+ throw feedbackCommentatorsResult.error;
const stakeholders = new Set();
@@ -446,7 +464,7 @@ export async function getFeedbackStakeholdersExceptMentionedUser({ feedbackId, e
stakeholders.add(feedbackOwnerResult.data[0].user_id);
}
- feedbackCommentatorsResult.data.forEach(comment => {
+ feedbackCommentatorsResult.data.forEach((comment) => {
stakeholders.add(comment.user_id);
});
@@ -456,6 +474,7 @@ export async function getFeedbackStakeholdersExceptMentionedUser({ feedbackId, e
return Array.from(stakeholders);
} catch (error) {
+ console.log('error in getFeedbackStakeholdersExceptMentionedUser: ', error);
throw error;
}
}