diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..715f62fd --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +# Ready for docker-compose +REDIS_URL="redis://127.0.0.1:6379" +DATABASE_URL="postgres://username:password@127.0.0.1:5435/postgres?sslmode=disable" +NEXTAUTH_SECRET="secret_sauce" +NEXTAUTH_URL="http://localhost:3000" \ No newline at end of file diff --git a/README.md b/README.md index 0ccdf389..20400406 100644 --- a/README.md +++ b/README.md @@ -69,39 +69,35 @@ For pushing events ### Usage ```ts -import { Mixan } from '@mixan/sdk'; +import { MixanWeb } from '@mixan/sdk-web'; -const mixan = new Mixan({ +// import { MixanNative } from '@mixan/sdk-native'; + +const mixan = new MixanWeb({ clientId: 'uuid', - clientSecret: 'uuid', url: 'http://localhost:8080/api/sdk', batchInterval: 10000, verbose: false, - saveProfileId(id) { - // Web - localStorage.setItem('@profileId', id); - // // react-native-mmkv - // mmkv.setItem('@profileId', id) - }, - removeProfileId() { - // Web - localStorage.removeItem('@profileId'); - // // react-native-mmkv - // mmkv.delete('@profileId') - }, - getProfileId() { - // Web - return localStorage.getItem('@profileId'); - // // react-native-mmkv - // return mmkv.getString('@profileId') - }, + trackIp: true, }); +// const mixan = new MixanNative({ +// clientId: 'uuid', +// clientSecret: 'uuid', +// url: 'http://localhost:8080/api/sdk', +// batchInterval: 10000, +// verbose: false, +// trackIp: true, +// }); + // Call this before you send any events // It will create a anonymous profile // This profile will be merged if you call `setUser` in a later stage mixan.init(); +// tracks all outgoing links as a `link_out` event +mixan.trackOutgoingLinks(); + mixan.setUser({ id: 'id', first_name: 'John', @@ -125,10 +121,13 @@ mixan.event('sign_in', { provider: 'gmail', }); -// short hand for 'screen_view', can also take any properties -mixan.screenView('Profile', { - id: '123', - // any other properties, url, public +// Screen view for web +mixan.screenView(); + +// Screen view for native +mixan.screenView('Article', { + id: '3', + title: 'Nice article here', }); // Call this when a user is logged out. @@ -150,6 +149,11 @@ We use https://cron-job.org (free) to handle our cronjobs, you can use any provi - **https://domain.com/api/cron/cache/update** Will update the memory cache - **https://domain.com/api/cron/events/enrich** Enrich events (adds duration etc) +## Development + +1. Run `docker-compose up -d` to get redis and postgres running +2. Then `pnpm dev` to boot the web and worker (queue) + ## Screenshots ![Line chart](images/line.png) diff --git a/apps/test/package.json b/apps/test/package.json index 61a37fd1..f36fd504 100644 --- a/apps/test/package.json +++ b/apps/test/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev", + "dev": "next dev -p 3002", "build": "next build", "start": "next start", "lint": "eslint .", diff --git a/apps/test/src/analytics.ts b/apps/test/src/analytics.ts index 32ec747f..6296f019 100644 --- a/apps/test/src/analytics.ts +++ b/apps/test/src/analytics.ts @@ -2,10 +2,13 @@ import { MixanWeb } from '@mixan-test/sdk-web'; export const mixan = new MixanWeb({ verbose: true, - url: process.env.NEXT_PUBLIC_MIXAN_URL!, - clientId: process.env.NEXT_PUBLIC_MIXAN_CLIENT_ID!, - clientSecret: process.env.NEXT_PUBLIC_MIXAN_CLIENT_SECRET!, + url: 'http://localhost:3000/api/sdk', + clientId: '568b4ed1-5d00-4f27-88a7-b8959e6674bd', + clientSecret: '1e362905-d352-44c4-9263-e037a2ad52fb', trackIp: true, }); +mixan.init({ + appVersion: '1.0.0', +}); mixan.trackOutgoingLinks(); diff --git a/apps/test/src/pages/_app.tsx b/apps/test/src/pages/_app.tsx index a27e8894..89aa1f5c 100644 --- a/apps/test/src/pages/_app.tsx +++ b/apps/test/src/pages/_app.tsx @@ -3,11 +3,10 @@ import { mixan } from '@/analytics'; import type { AppProps } from 'next/app'; import { useRouter } from 'next/router'; -mixan.init(); - export default function MyApp({ Component, pageProps }: AppProps) { const router = useRouter(); useEffect(() => { + mixan.screenView(); return router.events.on('routeChangeComplete', () => { mixan.screenView(); }); diff --git a/apps/web/.env.example b/apps/web/.env.example deleted file mode 100644 index c1464a2f..00000000 --- a/apps/web/.env.example +++ /dev/null @@ -1,25 +0,0 @@ -# Since the ".env" file is gitignored, you can use the ".env.example" file to -# build a new ".env" file when you clone the repo. Keep this file up-to-date -# when you add new variables to `.env`. - -# This file will be committed to version control, so make sure not to have any -# secrets in it. If you are cloning this repo, create a copy of this file named -# ".env" and populate it with your secrets. - -# When adding additional environment variables, the schema in "/src/env.mjs" -# should be updated accordingly. - -# Prisma -# https://www.prisma.io/docs/reference/database-reference/connection-urls#env -DATABASE_URL="file:./db.sqlite" - -# Next Auth -# You can generate a new secret on the command line with: -# openssl rand -base64 32 -# https://next-auth.js.org/configuration/options#secret -# NEXTAUTH_SECRET="" -NEXTAUTH_URL="http://localhost:3000" - -# Next Auth Discord Provider -DISCORD_CLIENT_ID="" -DISCORD_CLIENT_SECRET="" diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 959ac96c..e5bcbe13 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -7,9 +7,13 @@ await import('./src/env.mjs'); /** @type {import("next").NextConfig} */ const config = { reactStrictMode: true, - transpilePackages: [], + transpilePackages: ['@mixan/queue'], eslint: { ignoreDuringBuilds: true }, typescript: { ignoreBuildErrors: true }, + experimental: { + // Avoid "Critical dependency: the request of a dependency is an expression" + serverComponentsExternalPackages: ['bullmq'], + }, /** * If you are using `appDir` then you must comment the below `i18n` config out. * diff --git a/apps/web/package.json b/apps/web/package.json index 14a797af..3ccb662d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,19 +3,19 @@ "version": "0.1.0", "private": true, "scripts": { - "postinstall": "prisma generate", - "dev": "next dev", + "dev": "pnpm with-env next dev", "build": "next build", "start": "next start", "lint": "eslint .", "format": "prettier --write \"**/*.{tsx,mjs,ts,md,json}\"", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "with-env": "dotenv -e ../../.env -c --" }, "dependencies": { "@hookform/resolvers": "^3.3.2", + "@mixan/db": "workspace:^", + "@mixan/queue": "workspace:^", "@mixan/types": "workspace:*", - "@next-auth/prisma-adapter": "^1.0.7", - "@prisma/client": "^5.1.1", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-aspect-ratio": "^1.0.3", "@radix-ui/react-avatar": "^1.0.4", @@ -83,7 +83,6 @@ "postcss": "^8.4.27", "prettier": "^3.0.3", "prettier-plugin-tailwindcss": "^0.5.1", - "prisma": "^5.1.1", "tailwindcss": "^3.3.3", "typescript": "^5.2.2" }, diff --git a/apps/web/src/components/projects/table.tsx b/apps/web/src/components/projects/table.tsx index 6247992b..abb4813d 100644 --- a/apps/web/src/components/projects/table.tsx +++ b/apps/web/src/components/projects/table.tsx @@ -1,7 +1,8 @@ import { formatDate } from '@/utils/date'; -import type { Project as IProject } from '@prisma/client'; import type { ColumnDef } from '@tanstack/react-table'; +import type { Project as IProject } from '@mixan/db'; + import { ProjectActions } from './ProjectActions'; export type Project = IProject; diff --git a/apps/web/src/modals/AddClient.tsx b/apps/web/src/modals/AddClient.tsx index 9366b818..c4c62c03 100644 --- a/apps/web/src/modals/AddClient.tsx +++ b/apps/web/src/modals/AddClient.tsx @@ -4,7 +4,6 @@ import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; import { Combobox } from '@/components/ui/combobox'; import { Label } from '@/components/ui/label'; -import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { toast } from '@/components/ui/use-toast'; import { useOrganizationParams } from '@/hooks/useOrganizationParams'; import { useRefetchActive } from '@/hooks/useRefetchActive'; @@ -144,8 +143,12 @@ export default function CreateProject() { name="withCors" control={control} render={({ field }) => ( -