diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 06d71ff..69541be 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -7,6 +7,10 @@ export default defineConfig({ integrations: [ starlightBlog({ title: 'The Best Blog Ever', + sidebar: [ + { + } + ], authors: { vince: { name: 'Vince', diff --git a/docs/src/content/docs/general/user-permissions.md b/docs/src/content/docs/general/user-permissions.md index 1b7c340..3dc2d4d 100644 --- a/docs/src/content/docs/general/user-permissions.md +++ b/docs/src/content/docs/general/user-permissions.md @@ -30,9 +30,7 @@ entity User {=psl credits Int @default(3) relatedObject RelatedObject[] externalAuthAssociations SocialLogin[] - contactFormMessages ContactFormMessage[] - referrer Referrer? @relation(fields: [referrerId], references: [id]) - referrerId Int? + contactFormMessages ContactFormMessage[] psl=} ``` diff --git a/main.wasp b/main.wasp index f853336..b0f8258 100644 --- a/main.wasp +++ b/main.wasp @@ -102,9 +102,7 @@ entity User {=psl credits Int @default(3) relatedObject RelatedObject[] externalAuthAssociations SocialLogin[] - contactFormMessages ContactFormMessage[] - referrer Referrer? @relation(fields: [referrerId], references: [id]) - referrerId Int? + contactFormMessages ContactFormMessage[] psl=} entity SocialLogin {=psl @@ -138,21 +136,26 @@ entity ContactFormMessage {=psl psl=} entity DailyStats {=psl - id Int @id @default(autoincrement()) - date DateTime @default(now()) @unique - userCount Int @default(0) - paidUserCount Int @default(0) - userDelta Int @default(0) - paidUserDelta Int @default(0) - totalRevenue Float @default(0) - totalProfit Float @default(0) + 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 Referrer {=psl - id Int @id @default(autoincrement()) - name String @default("unknown") @unique - count Int @default(0) - users User[] +entity PageViewSource {=psl + date DateTime @default(now()) + name String @unique + visitors Int + dailyStats DailyStats? @relation(fields: [dailyStatsId], references: [id]) + dailyStatsId Int? + @@id([date, name]) psl=} entity Logs {=psl @@ -298,16 +301,6 @@ action updateUserById { entities: [User] } -action saveReferrer { - fn: import { saveReferrer } from "@server/actions.js", - entities: [Referrer] -} - -action UpdateUserReferrer { - fn: import { updateUserReferrer } from "@server/actions.js", - entities: [User, Referrer] -} - // 📚 Queries query getRelatedObjects { @@ -320,21 +313,11 @@ query getDailyStats { entities: [User, DailyStats] } -query getReferrerStats { - fn: import { getReferrerStats } from "@server/queries.js", - entities: [User, Referrer] -} - query getPaginatedUsers { fn: import { getPaginatedUsers } from "@server/queries.js", entities: [User] } -query getPlausibleStats { - fn: import { getPlausibleStats } from "@server/queries.js", - entities: [User, Logs] -} - /* * 📡 These are custom Wasp API Endpoints. Use them for callbacks, webhooks, etc. * https://wasp-lang.dev/docs/advanced/apis @@ -369,8 +352,8 @@ job dailyStats { }, schedule: { // every hour - cron: "0 * * * *" - // cron: "* * * * *" + // cron: "0 * * * *" + cron: "* * * * *" }, - entities: [User, DailyStats, Logs] + entities: [User, DailyStats, Logs, PageViewSource] } diff --git a/migrations/20231127110538_daily_page_views/migration.sql b/migrations/20231127110538_daily_page_views/migration.sql new file mode 100644 index 0000000..ede4c13 --- /dev/null +++ b/migrations/20231127110538_daily_page_views/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "DailyStats" ADD COLUMN "dailyPageViewsDelta" DOUBLE PRECISION NOT NULL DEFAULT 0, +ADD COLUMN "totalPageViews" INTEGER NOT NULL DEFAULT 0; diff --git a/migrations/20231127113005_daily_pageviews_delta/migration.sql b/migrations/20231127113005_daily_pageviews_delta/migration.sql new file mode 100644 index 0000000..3fe2899 --- /dev/null +++ b/migrations/20231127113005_daily_pageviews_delta/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - You are about to alter the column `dailyPageViewsDelta` on the `DailyStats` table. The data in that column could be lost. The data in that column will be cast from `DoublePrecision` to `Integer`. + +*/ +-- AlterTable +ALTER TABLE "DailyStats" ALTER COLUMN "dailyPageViewsDelta" SET DEFAULT 0, +ALTER COLUMN "dailyPageViewsDelta" SET DATA TYPE INTEGER; diff --git a/migrations/20231127114535_prev_day_views_change_percent/migration.sql b/migrations/20231127114535_prev_day_views_change_percent/migration.sql new file mode 100644 index 0000000..f727a3d --- /dev/null +++ b/migrations/20231127114535_prev_day_views_change_percent/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - You are about to drop the column `dailyPageViewsDelta` on the `DailyStats` table. All the data in the column will be lost. + - You are about to drop the column `totalPageViews` on the `DailyStats` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "DailyStats" DROP COLUMN "dailyPageViewsDelta", +DROP COLUMN "totalPageViews", +ADD COLUMN "prevDayViewsChangePercent" TEXT NOT NULL DEFAULT '0', +ADD COLUMN "totalViews" INTEGER NOT NULL DEFAULT 0; diff --git a/migrations/20231127143949_page_view_source/migration.sql b/migrations/20231127143949_page_view_source/migration.sql new file mode 100644 index 0000000..d1c6454 --- /dev/null +++ b/migrations/20231127143949_page_view_source/migration.sql @@ -0,0 +1,15 @@ +-- CreateTable +CREATE TABLE "PageViewSource" ( + "id" SERIAL NOT NULL, + "name" TEXT NOT NULL, + "visitors" INTEGER NOT NULL, + "dailyStatsId" INTEGER, + + CONSTRAINT "PageViewSource_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "PageViewSource_name_key" ON "PageViewSource"("name"); + +-- AddForeignKey +ALTER TABLE "PageViewSource" ADD CONSTRAINT "PageViewSource_dailyStatsId_fkey" FOREIGN KEY ("dailyStatsId") REFERENCES "DailyStats"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/migrations/20231127144953_page_view_source/migration.sql b/migrations/20231127144953_page_view_source/migration.sql new file mode 100644 index 0000000..11dae7f --- /dev/null +++ b/migrations/20231127144953_page_view_source/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "PageViewSource" ADD COLUMN "date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/migrations/20231127145135_date_utc/migration.sql b/migrations/20231127145135_date_utc/migration.sql new file mode 100644 index 0000000..328d528 --- /dev/null +++ b/migrations/20231127145135_date_utc/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to drop the column `date` on the `PageViewSource` table. All the data in the column will be lost. + - Added the required column `dateUTC` to the `PageViewSource` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "PageViewSource" DROP COLUMN "date", +ADD COLUMN "dateUTC" TEXT NOT NULL; diff --git a/migrations/20231127145351_date/migration.sql b/migrations/20231127145351_date/migration.sql new file mode 100644 index 0000000..bf6106f --- /dev/null +++ b/migrations/20231127145351_date/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - You are about to drop the column `dateUTC` on the `PageViewSource` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "PageViewSource" DROP COLUMN "dateUTC", +ADD COLUMN "dat" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/migrations/20231127145440_unique_date/migration.sql b/migrations/20231127145440_unique_date/migration.sql new file mode 100644 index 0000000..1bbe23e --- /dev/null +++ b/migrations/20231127145440_unique_date/migration.sql @@ -0,0 +1,13 @@ +/* + Warnings: + + - You are about to drop the column `dat` on the `PageViewSource` table. All the data in the column will be lost. + - A unique constraint covering the columns `[date]` on the table `PageViewSource` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "PageViewSource" DROP COLUMN "dat", +ADD COLUMN "date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; + +-- CreateIndex +CREATE UNIQUE INDEX "PageViewSource_date_key" ON "PageViewSource"("date"); diff --git a/migrations/20231127151321_composite_key/migration.sql b/migrations/20231127151321_composite_key/migration.sql new file mode 100644 index 0000000..f1592ea --- /dev/null +++ b/migrations/20231127151321_composite_key/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - The primary key for the `PageViewSource` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `id` on the `PageViewSource` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "PageViewSource" DROP CONSTRAINT "PageViewSource_pkey", +DROP COLUMN "id", +ADD CONSTRAINT "PageViewSource_pkey" PRIMARY KEY ("date", "name"); diff --git a/migrations/20231127151444_f/migration.sql b/migrations/20231127151444_f/migration.sql new file mode 100644 index 0000000..f2f66dc --- /dev/null +++ b/migrations/20231127151444_f/migration.sql @@ -0,0 +1,2 @@ +-- DropIndex +DROP INDEX "PageViewSource_date_key"; diff --git a/migrations/20231127161704_/migration.sql b/migrations/20231127161704_/migration.sql new file mode 100644 index 0000000..5e46ead --- /dev/null +++ b/migrations/20231127161704_/migration.sql @@ -0,0 +1,15 @@ +/* + Warnings: + + - You are about to drop the column `referrerId` on the `User` table. All the data in the column will be lost. + - You are about to drop the `Referrer` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "User" DROP CONSTRAINT "User_referrerId_fkey"; + +-- AlterTable +ALTER TABLE "User" DROP COLUMN "referrerId"; + +-- DropTable +DROP TABLE "Referrer"; diff --git a/src/client/App.tsx b/src/client/App.tsx index 0b079e2..7755d79 100644 --- a/src/client/App.tsx +++ b/src/client/App.tsx @@ -2,11 +2,8 @@ import './Main.css'; import AppNavBar from './components/AppNavBar'; import { useMemo, useEffect, ReactNode } from 'react'; import { useLocation } from 'react-router-dom'; -import { useReferrer, UNKOWN_REFERRER } from './hooks/useReferrer'; import useAuth from '@wasp/auth/useAuth'; import updateCurrentUser from '@wasp/actions/updateCurrentUser'; // TODO fix -import updateUserReferrer from '@wasp/actions/UpdateUserReferrer'; -import saveReferrer from '@wasp/actions/saveReferrer'; /** * use this component to wrap all child components @@ -15,7 +12,6 @@ import saveReferrer from '@wasp/actions/saveReferrer'; export default function App({ children }: { children: ReactNode }) { const location = useLocation(); const { data: user } = useAuth(); - const [referrer, setReferrer] = useReferrer(); const shouldDisplayAppNavBar = useMemo(() => { return location.pathname !== '/' && location.pathname !== '/login' && location.pathname !== '/signup'; @@ -34,26 +30,6 @@ export default function App({ children }: { children: ReactNode }) { } }, [user]); - useEffect(() => { - if (referrer && referrer.ref !== UNKOWN_REFERRER && !referrer.isSavedInDB) { - saveReferrer({ name: referrer.ref }); - setReferrer({ - ...referrer, - isSavedInDB: true, - }); - } - }, [referrer]); - - useEffect(() => { - if (user && referrer && !referrer.isSavedToUser && referrer.ref !== UNKOWN_REFERRER) { - updateUserReferrer({ name: referrer.ref }); - setReferrer({ - ...referrer, - isSavedToUser: true, - }); - } - }, [user, referrer]); - useEffect(() => { if (location.hash) { const id = location.hash.replace('#', ''); diff --git a/src/client/admin/components/ReferrerTable.tsx b/src/client/admin/components/ReferrerTable.tsx deleted file mode 100644 index 994755e..0000000 --- a/src/client/admin/components/ReferrerTable.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useQuery } from '@wasp/queries'; -import getReferrerStats from '@wasp/queries/getReferrerStats'; - -// We're using a simple, in-house analytics system that tracks referrers and page views. -// You could instead set up Google Analytics or Plausible and use their API for more detailed stats. -const ReferrerTable = () => { - const { data: referrers, isLoading: isReferrersLoading, error: referrersError } = useQuery(getReferrerStats); - - return ( -
- -

Top Referrers

- -
-
-
-
Source
-
-
-
Visitors
-
-
-
Conversion
- % of visitors that register -
-
-
Sales
-
-
- - {referrers && - referrers.length > 0 && - referrers.map((ref) => ( -
-
-

{ref.name}

-
- -
-

{ref.count}

-
- -
-

{ref.users.length > 0 ? Math.round((ref.users.length / ref.count)*100) : '0'}%

-
- -
-

--

-
-
- ))} -
-
- ); -}; - -export default ReferrerTable; diff --git a/src/client/admin/components/RevenueAndProfitChart.tsx b/src/client/admin/components/RevenueAndProfitChart.tsx index 447362d..2cc70ef 100644 --- a/src/client/admin/components/RevenueAndProfitChart.tsx +++ b/src/client/admin/components/RevenueAndProfitChart.tsx @@ -11,7 +11,7 @@ const options: ApexOptions = { }, colors: ['#3C50E0', '#80CAEE'], chart: { - fontFamily: 'Satoshi, sans-serif', + fontFamily: 'Satoshi, sans-serif', height: 335, type: 'area', dropShadow: { @@ -175,18 +175,22 @@ const RevenueAndProfitChart = ({ weeklyStats, isLoading }: DailyStatsProps) => { }, [dailyRevenueArray]); useEffect(() => { - console.log('ooptions categories: ', options?.xaxis?.categories); - console.log('days of week arr: ', daysOfWeekArr); - if (!!daysOfWeekArr && daysOfWeekArr?.length > 0) { + if (!!daysOfWeekArr && daysOfWeekArr?.length > 0 && !!dailyRevenueArray && dailyRevenueArray?.length > 0) { setChartOptions({ ...options, xaxis: { ...options.xaxis, categories: daysOfWeekArr, }, + yaxis: { + ...options.yaxis, + // get the min & max values to the neareast hundred + max: Math.ceil(Math.max(...dailyRevenueArray) / 100) * 100, + min: Math.floor(Math.min(...dailyRevenueArray) / 100) * 100, + }, }); } - }, [daysOfWeekArr]); + }, [daysOfWeekArr, dailyRevenueArray]); return (
diff --git a/src/client/admin/components/SourcesTable.tsx b/src/client/admin/components/SourcesTable.tsx new file mode 100644 index 0000000..6f04866 --- /dev/null +++ b/src/client/admin/components/SourcesTable.tsx @@ -0,0 +1,49 @@ +import { PageViewSource } from "@wasp/entities"; + +const SourcesTable = ({ sources } : { sources: PageViewSource[] | undefined }) => { + + return ( +
+ +

Top Sources

+ +
+
+
+
Source
+
+
+
Visitors
+
+
+
Sales
+
+
+ + {sources && + sources.length > 0 ? + sources.map((source) => ( +
+
+

{source.name}

+
+ +
+

{source.visitors}

+
+ +
+

--

+
+
+ )) : ( +
+

No data to display

+
+ )} +
+
+ ); +}; + +export default SourcesTable; diff --git a/src/client/admin/components/SwitcherOne.tsx b/src/client/admin/components/SwitcherOne.tsx index cbe61a7..3ac1cd9 100644 --- a/src/client/admin/components/SwitcherOne.tsx +++ b/src/client/admin/components/SwitcherOne.tsx @@ -19,7 +19,7 @@ const SwitcherOne = ({ user, updateUserById}: { user?: Partial, updateUser />
diff --git a/src/client/admin/components/TotalPaidViewsCard.tsx b/src/client/admin/components/TotalPaidViewsCard.tsx index 50b6db7..1816e8b 100644 --- a/src/client/admin/components/TotalPaidViewsCard.tsx +++ b/src/client/admin/components/TotalPaidViewsCard.tsx @@ -1,13 +1,13 @@ import { UpArrow, DownArrow } from "../images/icon/icons-arrows"; type PageViewsStats = { - totalPageViews: string | undefined; - dailyChangePercentage: string | undefined; + totalPageViews: number | undefined; + prevDayViewsChangePercent: string | undefined; } -const TotalPageViewsCard = ({ totalPageViews, dailyChangePercentage } : PageViewsStats ) => { +const TotalPageViewsCard = ({ totalPageViews, prevDayViewsChangePercent } : PageViewsStats ) => { - const isDeltaPositive = parseInt(dailyChangePercentage || '') > 0; + const isDeltaPositive = parseInt(prevDayViewsChangePercent || '') > 0; return (
@@ -37,11 +37,11 @@ const TotalPageViewsCard = ({ totalPageViews, dailyChangePercentage } : PageView Total page views
- {dailyChangePercentage && parseInt(dailyChangePercentage) !== 0 && ( + {prevDayViewsChangePercent && parseInt(prevDayViewsChangePercent) !== 0 && ( - {dailyChangePercentage}%{parseInt(dailyChangePercentage) > 0 ? : } + {prevDayViewsChangePercent}%{parseInt(prevDayViewsChangePercent) > 0 ? : } )}
diff --git a/src/client/admin/components/TotalRevenueCard.tsx b/src/client/admin/components/TotalRevenueCard.tsx index d838315..e632166 100644 --- a/src/client/admin/components/TotalRevenueCard.tsx +++ b/src/client/admin/components/TotalRevenueCard.tsx @@ -9,18 +9,15 @@ const TotalRevenueCard = ({dailyStats, weeklyStats, isLoading}: DailyStatsProps) }, [weeklyStats]); const deltaPercentage = useMemo(() => { - if ( !weeklyStats || isLoading) return; + if ( !weeklyStats || weeklyStats.length < 2 || isLoading) return; + if ( weeklyStats[1]?.totalRevenue === 0 || weeklyStats[0]?.totalRevenue === 0 ) return 0; + weeklyStats.sort((a, b) => b.id - a.id); console.log('weeklyStats[1]?.totalRevenue; ', !!weeklyStats && weeklyStats) const percentage = ((weeklyStats[0].totalRevenue - weeklyStats[1]?.totalRevenue) / weeklyStats[1]?.totalRevenue) * 100; return Math.floor(percentage); }, [weeklyStats]); - useEffect(() => { - console.log('deltaPercentage; ', deltaPercentage) - console.log('weeklyStats; ', weeklyStats) - }, [deltaPercentage]) - return (
diff --git a/src/client/admin/components/UsersTable.tsx b/src/client/admin/components/UsersTable.tsx index 8b99160..8c3161a 100644 --- a/src/client/admin/components/UsersTable.tsx +++ b/src/client/admin/components/UsersTable.tsx @@ -32,8 +32,8 @@ const UsersTable = () => { return (
-
- Filters: +
+ Filters: