From 24b1e4788025d60d0f4a392534be02a9e7ef9129 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:12:23 +0200 Subject: [PATCH 01/13] Create schema.prisma --- template/app/schema.prisma | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 template/app/schema.prisma diff --git a/template/app/schema.prisma b/template/app/schema.prisma new file mode 100644 index 00000000..ca1ce0cb --- /dev/null +++ b/template/app/schema.prisma @@ -0,0 +1,10 @@ +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + + From 5a67090ed0147ad22da5308f549e11818eeee0f6 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:53:21 +0200 Subject: [PATCH 02/13] update admin pages --- template/app/main.wasp | 109 +---- template/app/schema.prisma | 104 +++++ .../analytics/AnalyticsDashboardPage.tsx | 13 +- .../dashboards/users/UsersDashboardPage.tsx | 8 +- .../admin/elements/calendar/CalendarPage.tsx | 350 ++++++--------- .../src/admin/elements/charts/ChartsPage.tsx | 8 +- .../admin/elements/forms/FormElementsPage.tsx | 8 +- .../admin/elements/forms/FormLayoutsPage.tsx | 8 +- .../admin/elements/settings/SettingsPage.tsx | 338 +++++++-------- .../admin/elements/ui-elements/AlertsPage.tsx | 8 +- .../elements/ui-elements/ButtonsPage.tsx | 402 +++++++++--------- .../app/src/admin/layout/DefaultLayout.tsx | 6 +- template/app/src/admin/layout/Header.tsx | 6 +- template/app/src/admin/useIsUserAdmin.ts | 13 + template/app/src/messages/MessagesPage.tsx | 5 +- 15 files changed, 656 insertions(+), 730 deletions(-) create mode 100644 template/app/src/admin/useIsUserAdmin.ts diff --git a/template/app/main.wasp b/template/app/main.wasp index 0f81d0e8..ddebe52b 100644 --- a/template/app/main.wasp +++ b/template/app/main.wasp @@ -1,6 +1,6 @@ app OpenSaaS { wasp: { - version: "^0.13.2" + version: "^0.14.0" }, title: "My Open SaaS App", @@ -60,7 +60,6 @@ app OpenSaaS { }, db: { - system: PostgreSQL, // Run `wasp db seed` to seed the database with the seed functions below: seeds: [ // Populates the database with a bunch of fake users to work with during development. @@ -85,29 +84,6 @@ app OpenSaaS { }, } -entity GptResponse {=psl - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - user User @relation(fields: [userId], references: [id]) - userId String - - content String -psl=} - -entity Task {=psl - id String @id @default(uuid()) - createdAt DateTime @default(now()) - - user User @relation(fields: [userId], references: [id]) - userId String - - description String - time String @default("1") - isDone Boolean @default(false) -psl=} - route LandingPageRoute { path: "/", to: LandingPage } page LandingPage { component: import LandingPage from "@src/client/landing-page/LandingPage" @@ -188,29 +164,6 @@ job emailChecker { } //#region User -entity User {=psl - id String @id @default(uuid()) - createdAt DateTime @default(now()) - - email String? @unique - username String? @unique - lastActiveTimestamp DateTime @default(now()) - isAdmin Boolean @default(false) - - stripeId String? @unique - checkoutSessionId String? - subscriptionStatus String? // 'active', 'canceled', 'past_due', 'deleted' - subscriptionPlan String? // 'hobby', 'pro' - sendEmail Boolean @default(false) - datePaid DateTime? - credits Int @default(3) - - gptResponses GptResponse[] - contactFormMessages ContactFormMessage[] - tasks Task[] - files File[] -psl=} - route AccountRoute { path: "/account", to: AccountPage } page AccountPage { authRequired: true, @@ -279,19 +232,6 @@ query getDownloadFileSignedURL { fn: import { getDownloadFileSignedURL } from "@src/file-upload/operations", entities: [User, File] } - -entity File {=psl - id String @id @default(uuid()) - createdAt DateTime @default(now()) - - user User @relation(fields: [userId], references: [id]) - userId String - - name String - type String - key String - uploadUrl String -psl=} //#endregion //#region Analytics @@ -311,41 +251,6 @@ job dailyStatsJob { }, entities: [User, DailyStats, Logs, PageViewSource] } - -entity DailyStats {=psl - id Int @id @default(autoincrement()) - date DateTime @default(now()) @unique - - totalViews Int @default(0) - prevDayViewsChangePercent String @default("0") - userCount Int @default(0) - paidUserCount Int @default(0) - userDelta Int @default(0) - paidUserDelta Int @default(0) - totalRevenue Float @default(0) - totalProfit Float @default(0) - - sources PageViewSource[] -psl=} - -entity PageViewSource {=psl - @@id([date, name]) - name String - date DateTime @default(now()) - - dailyStats DailyStats? @relation(fields: [dailyStatsId], references: [id]) - dailyStatsId Int? - - visitors Int -psl=} - -entity Logs {=psl - id Int @id @default(autoincrement()) - createdAt DateTime @default(now()) - - message String - level String -psl=} //#endregion //#region Admin Dashboard @@ -413,16 +318,4 @@ page AdminMessagesPage { authRequired: true, component: import AdminMessages from "@src/messages/MessagesPage" } - -entity ContactFormMessage {=psl - id String @id @default(uuid()) - createdAt DateTime @default(now()) - - user User @relation(fields: [userId], references: [id]) - userId String - - content String - isRead Boolean @default(false) - repliedAt DateTime? -psl=} //#endregion diff --git a/template/app/schema.prisma b/template/app/schema.prisma index ca1ce0cb..4d23c902 100644 --- a/template/app/schema.prisma +++ b/template/app/schema.prisma @@ -7,4 +7,108 @@ generator client { provider = "prisma-client-js" } +model User { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + email String? @unique + username String? @unique + lastActiveTimestamp DateTime @default(now()) + isAdmin Boolean @default(false) + + stripeId String? @unique + checkoutSessionId String? + subscriptionStatus String? // 'active', 'canceled', 'past_due', 'deleted' + subscriptionPlan String? // 'hobby', 'pro' + sendEmail Boolean @default(false) + datePaid DateTime? + credits Int @default(3) + + gptResponses GptResponse[] + contactFormMessages ContactFormMessage[] + tasks Task[] + files File[] +} + +model GptResponse { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id]) + userId String + + content String +} + +model Task { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id]) + userId String + + description String + time String @default("1") + isDone Boolean @default(false) +} + +model File { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id]) + userId String + + name String + type String + key String + uploadUrl String +} + +model DailyStats { + id Int @id @default(autoincrement()) + date DateTime @default(now()) @unique + + totalViews Int @default(0) + prevDayViewsChangePercent String @default("0") + userCount Int @default(0) + paidUserCount Int @default(0) + userDelta Int @default(0) + paidUserDelta Int @default(0) + totalRevenue Float @default(0) + totalProfit Float @default(0) + + sources PageViewSource[] +} + +model PageViewSource { + @@id([date, name]) + name String + date DateTime @default(now()) + + dailyStats DailyStats? @relation(fields: [dailyStatsId], references: [id]) + dailyStatsId Int? + + visitors Int +} + +model Logs { + id Int @id @default(autoincrement()) + createdAt DateTime @default(now()) + + message String + level String +} + +model ContactFormMessage { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + + user User @relation(fields: [userId], references: [id]) + userId String + + content String + isRead Boolean @default(false) + repliedAt DateTime? +} \ No newline at end of file diff --git a/template/app/src/admin/dashboards/analytics/AnalyticsDashboardPage.tsx b/template/app/src/admin/dashboards/analytics/AnalyticsDashboardPage.tsx index 6f89ae56..10cf55cf 100644 --- a/template/app/src/admin/dashboards/analytics/AnalyticsDashboardPage.tsx +++ b/template/app/src/admin/dashboards/analytics/AnalyticsDashboardPage.tsx @@ -1,4 +1,4 @@ -import { type User } from 'wasp/entities'; +import { type AuthUser } from 'wasp/auth'; import { useQuery, getDailyStats } from 'wasp/client/operations'; import TotalSignupsCard from './TotalSignupsCard'; import TotalPageViewsCard from './TotalPageViewsCard'; @@ -7,18 +7,15 @@ import TotalRevenueCard from './TotalRevenueCard'; import RevenueAndProfitChart from './RevenueAndProfitChart'; import SourcesTable from './PageViewSourcesTable'; import DefaultLayout from '../../layout/DefaultLayout'; -import { useHistory } from 'react-router-dom'; +import { useIsUserAdmin } from '../../useIsUserAdmin' -const Dashboard = ({ user }: { user: User }) => { - const history = useHistory(); - if (!user.isAdmin) { - history.push('/'); - } +const Dashboard = ({ user }: { user: AuthUser }) => { + useIsUserAdmin({ user }) const { data: stats, isLoading, error } = useQuery(getDailyStats); return ( - +
{ + useIsUserAdmin({user}) -const Users = () => { return ( - +
diff --git a/template/app/src/admin/elements/calendar/CalendarPage.tsx b/template/app/src/admin/elements/calendar/CalendarPage.tsx index 3e6a6557..14b5572f 100644 --- a/template/app/src/admin/elements/calendar/CalendarPage.tsx +++ b/template/app/src/admin/elements/calendar/CalendarPage.tsx @@ -1,265 +1,189 @@ +import { type AuthUser } from 'wasp/auth'; import Breadcrumb from '../../layout/Breadcrumb'; import DefaultLayout from '../../layout/DefaultLayout'; +import { useIsUserAdmin } from '../../useIsUserAdmin'; + +const Calendar = ({ user }: { user: AuthUser }) => { + useIsUserAdmin({ user }); -const Calendar = () => { return ( - - + + {/* */} -
- +
+
- - + - - - - - - {/* */} - - + - - - - - - {/* */} {/* */} - - - - - - - - + + + + + + + {/* */} {/* */} - - - - - - - - + + + + + + + {/* */} {/* */} - - - - - + + + + - - - {/* */} {/* */} - - - - - - - - + + + + + + + {/* */} diff --git a/template/app/src/admin/elements/charts/ChartsPage.tsx b/template/app/src/admin/elements/charts/ChartsPage.tsx index 93b0efd8..cd11ed8d 100644 --- a/template/app/src/admin/elements/charts/ChartsPage.tsx +++ b/template/app/src/admin/elements/charts/ChartsPage.tsx @@ -1,12 +1,16 @@ +import { type AuthUser } from 'wasp/auth'; import Breadcrumb from '../../layout/Breadcrumb'; import DefaultLayout from '../../layout/DefaultLayout'; import BarChart from './BarChart'; import PieChart from './PieChart'; import DataStats from './DataStatsChart'; +import { useIsUserAdmin } from '../../useIsUserAdmin'; + +const Chart = ({ user }: { user: AuthUser }) => { + useIsUserAdmin({ user }); -const Chart = () => { return ( - +
diff --git a/template/app/src/admin/elements/forms/FormElementsPage.tsx b/template/app/src/admin/elements/forms/FormElementsPage.tsx index c5d76a31..dc873217 100644 --- a/template/app/src/admin/elements/forms/FormElementsPage.tsx +++ b/template/app/src/admin/elements/forms/FormElementsPage.tsx @@ -1,12 +1,16 @@ +import { type AuthUser } from 'wasp/auth'; import Breadcrumb from '../../layout/Breadcrumb'; import DefaultLayout from '../../layout/DefaultLayout'; import CheckboxOne from './CheckboxOne'; import SwitcherOne from '../../dashboards/users/SwitcherOne'; import SwitcherTwo from './SwitcherTwo'; +import { useIsUserAdmin } from '../../useIsUserAdmin'; + +const FormElements = ({ user }: { user: AuthUser }) => { + useIsUserAdmin({ user }); -const FormElements = () => { return ( - +
diff --git a/template/app/src/admin/elements/forms/FormLayoutsPage.tsx b/template/app/src/admin/elements/forms/FormLayoutsPage.tsx index 28dd2da0..5dc30f43 100644 --- a/template/app/src/admin/elements/forms/FormLayoutsPage.tsx +++ b/template/app/src/admin/elements/forms/FormLayoutsPage.tsx @@ -1,9 +1,13 @@ +import { type AuthUser } from 'wasp/auth'; import Breadcrumb from '../../layout/Breadcrumb'; import DefaultLayout from '../../layout/DefaultLayout'; +import { useIsUserAdmin } from '../../useIsUserAdmin'; + +const FormLayout = ({ user }: { user: AuthUser }) => { + useIsUserAdmin({ user }); -const FormLayout = () => { return ( - +
diff --git a/template/app/src/admin/elements/settings/SettingsPage.tsx b/template/app/src/admin/elements/settings/SettingsPage.tsx index 4a20fcc4..140223b3 100644 --- a/template/app/src/admin/elements/settings/SettingsPage.tsx +++ b/template/app/src/admin/elements/settings/SettingsPage.tsx @@ -1,220 +1,209 @@ +import { type AuthUser } from 'wasp/auth'; import { FormEvent } from 'react'; import toast from 'react-hot-toast'; import Breadcrumb from '../../layout/Breadcrumb'; import DefaultLayout from '../../layout/DefaultLayout'; +import { useIsUserAdmin } from '../../useIsUserAdmin'; + +const SettingsPage = ({ user }: { user: AuthUser }) => { + useIsUserAdmin({ user }); -const SettingsPage = () => { const handleSubmit = (event: FormEvent) => { // TODO add toast provider / wrapper event.preventDefault(); - const confirmed = confirm("Are you sure you want to save the changes?"); + const confirmed = confirm('Are you sure you want to save the changes?'); if (confirmed) { - toast.success("Your changes have been saved successfully!"); + toast.success('Your changes have been saved successfully!'); } else { - toast.error("Your changes have not been saved!"); + toast.error('Your changes have not been saved!'); } }; return ( - -
- - + +
+ -
-
-
-
-

- Personal Information -

+
+
+
+
+

Personal Information

-
+
-
-
-
- Sunday - Sun +
+ Sunday + Sun - Monday - Mon + + Monday + Mon - Tuesday - Tue + + Tuesday + Tue - Wednesday - Wed + + Wednesday + Wed - Thursday - Thur + + Thursday + Thur - Friday - Fri + + Friday + Fri - Saturday - Sat + + Saturday + Sat
- - 1 - -
- - More - -
- +
+ 1 +
+ More +
+ Redesign Website - - 1 Dec - 2 Dec - + 1 Dec - 2 Dec
- - 2 - + + 2 - - 3 - + + 3 - - 4 - + + 4 - - 5 - + + 5 - - 6 - + + 6 - - 7 - + + 7
- - 8 - - - - 9 - - - - 10 - - - - 11 - - - - 12 - - - - 13 - - - - 14 - +
+ 8 + + 9 + + 10 + + 11 + + 12 + + 13 + + 14
- - 15 - - - - 16 - - - - 17 - - - - 18 - - - - 19 - - - - 20 - - - - 21 - +
+ 15 + + 16 + + 17 + + 18 + + 19 + + 20 + + 21
- - 22 - - - - 23 - - - - 24 - - - - 25 - -
- - More - -
- - App Design - - - 25 Dec - 27 Dec - +
+ 22 + + 23 + + 24 + + 25 +
+ More +
+ App Design + 25 Dec - 27 Dec
- - 26 - + + 26 - - 27 - + + 27 - - 28 - + + 28
- - 29 - - - - 30 - - - - 31 - - - - 1 - - - - 2 - - - - 3 - - - - 4 - +
+ 29 + + 30 + + 31 + + 1 + + 2 + + 3 + + 4