🧹 clean up duty 🧹
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -4,7 +4,6 @@
|
||||
},
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
|
||||
"eslint.workingDirectories": [
|
||||
{ "pattern": "apps/*/" },
|
||||
{ "pattern": "packages/*/" },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# openpanel
|
||||
# Openpanel
|
||||
|
||||
Openpanel is a simple analytics tool for logging events on web and react-native. My goal is to make a minimal mixpanel copy with the most basic features (for now).
|
||||
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
import { omit, prop, uniqBy } from 'ramda';
|
||||
|
||||
import { generateProfileId, getTime, toISOString } from '@openpanel/common';
|
||||
import type { Event, IServiceCreateEventPayload } from '@openpanel/db';
|
||||
import {
|
||||
createEvent as createClickhouseEvent,
|
||||
db,
|
||||
formatClickhouseDate,
|
||||
getSalts,
|
||||
} from '@openpanel/db';
|
||||
|
||||
import { parseIp } from '../src/utils/parseIp';
|
||||
import { parseUserAgent } from '../src/utils/parseUserAgent';
|
||||
|
||||
const clean = omit([
|
||||
'ip',
|
||||
'os',
|
||||
'ua',
|
||||
'url',
|
||||
'hash',
|
||||
'host',
|
||||
'path',
|
||||
'device',
|
||||
'screen',
|
||||
'hostname',
|
||||
'language',
|
||||
'referrer',
|
||||
'timezone',
|
||||
]);
|
||||
async function main() {
|
||||
const events = await db.event.findMany({
|
||||
where: {
|
||||
project_id: '4e2798cb-e255-4e9d-960d-c9ad095aabd7',
|
||||
name: 'screen_view',
|
||||
createdAt: {
|
||||
gte: new Date('2024-01-01'),
|
||||
lt: new Date('2024-02-04'),
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'asc',
|
||||
},
|
||||
});
|
||||
|
||||
const grouped: Record<string, Event[]> = {};
|
||||
let index = 0;
|
||||
for (const event of events.slice()) {
|
||||
// console.log(index, event.name, event.createdAt.toISOString());
|
||||
index++;
|
||||
|
||||
const properties = event.properties as Record<string, any>;
|
||||
|
||||
if (properties.ua?.includes('bot')) {
|
||||
// console.log('IGNORE', event.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!event.profile_id) {
|
||||
// console.log('IGNORE', event.id);
|
||||
continue;
|
||||
}
|
||||
const hej = grouped[event.profile_id];
|
||||
if (hej) {
|
||||
hej.push(event);
|
||||
} else {
|
||||
grouped[event.profile_id] = [event];
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Total users', Object.keys(grouped).length);
|
||||
|
||||
let uidx = -1;
|
||||
for (const profile_id of Object.keys(grouped)) {
|
||||
uidx++;
|
||||
console.log(`User index ${uidx}`);
|
||||
|
||||
const events = uniqBy(prop('createdAt'), grouped[profile_id] || []);
|
||||
|
||||
if (events) {
|
||||
let lastSessionStart = null;
|
||||
let screenViews = 0;
|
||||
let totalDuration = 0;
|
||||
console.log('new user...');
|
||||
let eidx = -1;
|
||||
for (const event of events) {
|
||||
eidx++;
|
||||
const prevEvent = events[eidx - 1];
|
||||
const prevEventAt = prevEvent?.createdAt;
|
||||
|
||||
const nextEvent = events[eidx + 1];
|
||||
|
||||
const properties = event.properties as Record<string, any>;
|
||||
const projectId = event.project_id;
|
||||
const path = properties.path!;
|
||||
const ip = properties.ip!;
|
||||
const origin = 'https://openpanel.kiddo.se';
|
||||
const ua = properties.ua!;
|
||||
const uaInfo = parseUserAgent(ua);
|
||||
const salts = await getSalts();
|
||||
const profileId = generateProfileId({
|
||||
salt: salts.current,
|
||||
origin,
|
||||
ip,
|
||||
ua,
|
||||
});
|
||||
|
||||
const geo = parseIp(ip);
|
||||
|
||||
const isNextEventNewSession =
|
||||
nextEvent &&
|
||||
nextEvent.createdAt.getTime() - event.createdAt.getTime() >
|
||||
1000 * 60 * 30;
|
||||
|
||||
const payload: IServiceCreateEventPayload = {
|
||||
name: event.name,
|
||||
profileId,
|
||||
projectId,
|
||||
properties: clean(properties),
|
||||
createdAt: event.createdAt.toISOString(),
|
||||
country: geo.country,
|
||||
city: geo.city,
|
||||
region: geo.region,
|
||||
continent: geo.continent,
|
||||
os: uaInfo.os,
|
||||
osVersion: uaInfo.osVersion,
|
||||
browser: uaInfo.browser,
|
||||
browserVersion: uaInfo.browserVersion,
|
||||
device: uaInfo.device,
|
||||
brand: uaInfo.brand,
|
||||
model: uaInfo.model,
|
||||
duration:
|
||||
nextEvent && !isNextEventNewSession
|
||||
? nextEvent.createdAt.getTime() - event.createdAt.getTime()
|
||||
: 0,
|
||||
path,
|
||||
referrer: properties?.referrer?.host ?? '', // TODO
|
||||
referrerName: properties?.referrer?.host ?? '', // TODO
|
||||
};
|
||||
|
||||
if (!prevEventAt) {
|
||||
lastSessionStart = await createSessionStart(payload);
|
||||
} else if (
|
||||
event.createdAt.getTime() - prevEventAt.getTime() >
|
||||
1000 * 60 * 30
|
||||
) {
|
||||
if (eidx > 0 && prevEventAt && lastSessionStart) {
|
||||
await createSessionEnd(prevEventAt, lastSessionStart, {
|
||||
screenViews,
|
||||
totalDuration,
|
||||
});
|
||||
totalDuration = 0;
|
||||
screenViews = 0;
|
||||
lastSessionStart = await createSessionStart(payload);
|
||||
}
|
||||
}
|
||||
|
||||
screenViews++;
|
||||
totalDuration += payload.duration;
|
||||
await createEvent(payload);
|
||||
} // for each user event
|
||||
|
||||
const prevEventAt = events[events.length - 1]?.createdAt;
|
||||
if (prevEventAt && lastSessionStart) {
|
||||
await createSessionEnd(prevEventAt, lastSessionStart, {
|
||||
screenViews,
|
||||
totalDuration,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createEvent(event: IServiceCreateEventPayload) {
|
||||
console.log(
|
||||
`Create ${event.name} - ${event.path} - ${formatClickhouseDate(
|
||||
event.createdAt
|
||||
)} - ${event.duration / 1000} sec`
|
||||
);
|
||||
await createClickhouseEvent(event);
|
||||
}
|
||||
|
||||
async function createSessionStart(event: IServiceCreateEventPayload) {
|
||||
const session: IServiceCreateEventPayload = {
|
||||
...event,
|
||||
duration: 0,
|
||||
name: 'session_start',
|
||||
createdAt: toISOString(getTime(event.createdAt) - 100),
|
||||
};
|
||||
|
||||
await createEvent(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
async function createSessionEnd(
|
||||
prevEventAt: Date,
|
||||
sessionStart: IServiceCreateEventPayload,
|
||||
options: {
|
||||
screenViews: number;
|
||||
totalDuration: number;
|
||||
}
|
||||
) {
|
||||
const properties: Record<string, unknown> = {};
|
||||
if (options.screenViews === 1) {
|
||||
properties.__bounce = true;
|
||||
} else {
|
||||
properties.__bounce = false;
|
||||
}
|
||||
|
||||
const session: IServiceCreateEventPayload = {
|
||||
...sessionStart,
|
||||
properties: {
|
||||
...properties,
|
||||
...sessionStart.properties,
|
||||
},
|
||||
duration: options.totalDuration,
|
||||
name: 'session_end',
|
||||
createdAt: toISOString(prevEventAt.getTime() + 10),
|
||||
};
|
||||
|
||||
await createEvent(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,18 +0,0 @@
|
||||
//@ts-nocheck
|
||||
|
||||
async function main() {
|
||||
const crypto = require('crypto');
|
||||
|
||||
function createHash(data, len) {
|
||||
return crypto
|
||||
.createHash('shake256', { outputLength: len })
|
||||
.update(data)
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
console.log(createHash('foo', 2));
|
||||
// 1af9
|
||||
console.log(createHash('foo', 32));
|
||||
// 1af97f7818a28edf}
|
||||
}
|
||||
main();
|
||||
@@ -18,7 +18,7 @@ import type { PostEventPayload } from '@openpanel/sdk';
|
||||
const SESSION_TIMEOUT = 1000 * 60 * 30;
|
||||
const SESSION_END_TIMEOUT = SESSION_TIMEOUT + 1000;
|
||||
|
||||
async function withTiming<T>(name: string, promise: T) {
|
||||
async function withTiming<T>(name: string, promise: Promise<T>) {
|
||||
try {
|
||||
const start = Date.now();
|
||||
const res = await promise;
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
|
||||
},
|
||||
"include": ["."],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleErrorToastOptions } from '@/app/_trpc/client';
|
||||
import { Card, CardActions, CardActionsItem } from '@/components/card';
|
||||
import { FullPageEmptyState } from '@/components/full-page-empty-state';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { pushModal } from '@/modals';
|
||||
import { api, handleErrorToastOptions } from '@/trpc/client';
|
||||
import { LayoutPanelTopIcon, Pencil, PlusIcon, Trash } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
@@ -184,7 +184,7 @@ export function EventDetails({ event, open, setOpen }: Props) {
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
value={item.value}
|
||||
onClick={item.onClick}
|
||||
onClick={() => item.onClick?.()}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -225,7 +225,7 @@ export function EventDetails({ event, open, setOpen }: Props) {
|
||||
className="w-full"
|
||||
onClick={() => setIsEditOpen(true)}
|
||||
>
|
||||
Customize "{name}"
|
||||
Customize "{name}"
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
} from '@/components/ui/sheet';
|
||||
import { api } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { toast } from 'sonner';
|
||||
@@ -78,7 +78,7 @@ export function EventEdit({ event, open, setOpen }: Props) {
|
||||
<Sheet open={open} onOpenChange={setOpen}>
|
||||
<SheetContent>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Edit "{name}"</SheetTitle>
|
||||
<SheetTitle>Edit "{name}"</SheetTitle>
|
||||
</SheetHeader>
|
||||
<div className="my-8 flex flex-col gap-8">
|
||||
<div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
SheetTrigger,
|
||||
} from '@/components/ui/sheet';
|
||||
import { Tooltip, TooltipContent } from '@/components/ui/tooltip';
|
||||
import { api } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { TooltipTrigger } from '@radix-ui/react-tooltip';
|
||||
import type { VariantProps } from 'class-variance-authority';
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function LayoutOrganizationSelector({
|
||||
.filter((item) => item.slug)
|
||||
.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.slug!,
|
||||
value: item.slug,
|
||||
})) ?? []
|
||||
}
|
||||
onChange={(value) => {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Widget, WidgetBody, WidgetHead } from '@/components/widget';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
SheetTrigger,
|
||||
} from '@/components/ui/sheet';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { PlusIcon, SendIcon } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
|
||||
import {
|
||||
Table,
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Widget, WidgetHead } from '@/components/widget';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
import type { IServiceMember, IServiceProject } from '@openpanel/db';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Widget, WidgetBody, WidgetHead } from '@/components/widget';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { SaveIcon } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -13,8 +14,6 @@ import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { api, handleError } from '../../_trpc/client';
|
||||
|
||||
const validation = z.object({
|
||||
name: z.string().min(1),
|
||||
});
|
||||
|
||||
@@ -5,7 +5,6 @@ import { notFound, redirect } from 'next/navigation';
|
||||
import {
|
||||
getCurrentProjects,
|
||||
getOrganizationBySlug,
|
||||
getProjectsByOrganizationSlug,
|
||||
isWaitlistUserAccepted,
|
||||
} from '@openpanel/db';
|
||||
|
||||
@@ -36,8 +35,8 @@ export default async function Page({ params: { organizationId } }: PageProps) {
|
||||
<LogoSquare className="mb-8 w-20 md:w-28" />
|
||||
<h1 className="text-3xl font-medium">Not quite there yet</h1>
|
||||
<div className="text-lg">
|
||||
We're still working on Openpanel, but we're not quite there yet.
|
||||
We'll let you know when we're ready to go!
|
||||
We're still working on Openpanel, but we're not quite
|
||||
there yet. We'll let you know when we're ready to go!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Button, buttonVariants } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { SaveIcon, WallpaperIcon } from 'lucide-react';
|
||||
@@ -14,8 +15,6 @@ import type { SubmitHandler } from 'react-hook-form';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { api, handleError } from '../_trpc/client';
|
||||
|
||||
const validation = z
|
||||
.object({
|
||||
organization: z.string().min(3),
|
||||
@@ -61,8 +60,8 @@ export function CreateOrganization() {
|
||||
<LogoSquare className="mb-4 w-20" />
|
||||
<h1 className="text-3xl font-medium">Nice job!</h1>
|
||||
<div className="mb-4">
|
||||
You're ready to start using our SDK. Save the client ID and secret (if
|
||||
you have any)
|
||||
You're ready to start using our SDK. Save the client ID and
|
||||
secret (if you have any)
|
||||
</div>
|
||||
<CreateClientSuccess {...mutation.data.client} />
|
||||
<div className="mt-4 flex gap-4">
|
||||
|
||||
@@ -18,8 +18,8 @@ export default async function Page() {
|
||||
<LogoSquare className="mb-8 w-20 md:w-28" />
|
||||
<h1 className="text-3xl font-medium">Not quite there yet</h1>
|
||||
<div className="text-lg">
|
||||
We're still working on Openpanel, but we're not quite there yet.
|
||||
We'll let you know when we're ready to go!
|
||||
We're still working on Openpanel, but we're not quite
|
||||
there yet. We'll let you know when we're ready to go!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,6 @@ export async function POST(request: Request) {
|
||||
return Response.json({ message: 'Webhook received!' });
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
export function GET() {
|
||||
return Response.json({ message: 'Hello World!' });
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { appRouter } from '@/server/api/root';
|
||||
import { appRouter } from '@/trpc/api/root';
|
||||
import { getAuth } from '@clerk/nextjs/server';
|
||||
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
|
||||
|
||||
@@ -7,7 +7,7 @@ const handler = (req: Request) =>
|
||||
endpoint: '/api/trpc',
|
||||
req,
|
||||
router: appRouter,
|
||||
async createContext({ req }) {
|
||||
createContext({ req }) {
|
||||
const session = getAuth(req as any);
|
||||
return {
|
||||
session,
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import Error from "next/error";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function GlobalError({ error }) {
|
||||
useEffect(() => {
|
||||
Sentry.captureException(error);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<html>
|
||||
<body>
|
||||
<Error />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
23
apps/dashboard/src/app/global-error.tsx
Normal file
23
apps/dashboard/src/app/global-error.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import * as Sentry from '@sentry/nextjs';
|
||||
|
||||
export default function GlobalError({
|
||||
error,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
useEffect(() => {
|
||||
Sentry.captureException(error);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<h1>Something went wrong</h1>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { TooltipProvider } from '@/components/ui/tooltip';
|
||||
import { ModalProvider } from '@/modals';
|
||||
import type { AppStore } from '@/redux';
|
||||
import makeStore from '@/redux';
|
||||
import { api } from '@/trpc/client';
|
||||
import { ClerkProvider, useAuth } from '@clerk/nextjs';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { httpLink } from '@trpc/client';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { pushModal, showConfirm } from '@/modals';
|
||||
import { api } from '@/trpc/client';
|
||||
import { clipboard } from '@/utils/clipboard';
|
||||
import { MoreHorizontal } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
@@ -11,13 +11,17 @@ import {
|
||||
import { MoonIcon, SunIcon } from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
|
||||
export default function DarkModeToggle() {
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function DarkModeToggle({ className }: Props) {
|
||||
const { setTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<Button variant="outline" size="icon" className={className}>
|
||||
<SunIcon className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<MoonIcon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Fragment } from 'react';
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import AnimateHeight from 'react-animate-height';
|
||||
|
||||
@@ -118,7 +118,7 @@ export function OverviewLiveHistogram({
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top">
|
||||
<div>{minute.count} active users</div>
|
||||
<div>@ {new Date(minute.date).toLocaleTimeString()}</div>
|
||||
<div>@ {new Date(minute.date).toLocaleTimeString()}</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { pushModal } from '@/modals';
|
||||
import { api } from '@/trpc/client';
|
||||
import { EyeIcon, Globe2Icon, LockIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { pushModal, showConfirm } from '@/modals';
|
||||
import { api } from '@/trpc/client';
|
||||
import { clipboard } from '@/utils/clipboard';
|
||||
import { MoreHorizontal } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { pushModal } from '@/modals';
|
||||
import { useDispatch, useSelector } from '@/redux';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { SaveIcon } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
import type { IChartInput } from '@openpanel/validation';
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import airplane from '@/lottie/airplane.json';
|
||||
import ballon from '@/lottie/ballon.json';
|
||||
import noData from '@/lottie/no-data.json';
|
||||
import { cn } from '@/utils/cn';
|
||||
import type { LottieComponentProps } from 'lottie-react';
|
||||
import Lottie from 'lottie-react';
|
||||
|
||||
const animations = {
|
||||
airplane,
|
||||
ballon,
|
||||
noData,
|
||||
};
|
||||
type Animations = keyof typeof animations;
|
||||
|
||||
export const ChartAnimation = ({
|
||||
name,
|
||||
...props
|
||||
}: Omit<LottieComponentProps, 'animationData'> & {
|
||||
name: Animations;
|
||||
}) => <Lottie animationData={animations[name]} loop={true} {...props} />;
|
||||
|
||||
export const ChartAnimationContainer = (
|
||||
props: React.ButtonHTMLAttributes<HTMLDivElement>
|
||||
) => (
|
||||
<div
|
||||
{...props}
|
||||
className={cn(
|
||||
'rounded-md border border-border bg-background p-8',
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import type { IChartSerie } from '@/server/api/routers/chart';
|
||||
import type { IChartSerie } from '@/trpc/api/routers/chart';
|
||||
|
||||
import type { IChartInput } from '@openpanel/validation';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { ColorSquare } from '@/components/color-square';
|
||||
import { fancyMinutes, useNumber } from '@/hooks/useNumerFormatter';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { theme } from '@/utils/theme';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { Area, AreaChart } from 'recharts';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
|
||||
import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
import {
|
||||
Area,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
|
||||
import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { getChartColor, theme } from '@/utils/theme';
|
||||
import { Bar, BarChart, CartesianGrid, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
|
||||
import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
import {
|
||||
CartesianGrid,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { theme } from '@/utils/theme';
|
||||
import WorldMap from 'react-svg-worldmap';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
|
||||
import { useChartContext } from './ChartProvider';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { AutoSizer } from '@/components/react-virtualized-auto-sizer';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { round } from '@/utils/math';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import { Pagination, usePagination } from '@/components/pagination';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
@@ -20,6 +19,7 @@ import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
|
||||
import { useMappings } from '@/hooks/useMappings';
|
||||
import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import { useSelector } from '@/redux';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
|
||||
import { PreviousDiffIndicator } from '../PreviousDiffIndicator';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import type { RouterOutputs } from '@/app/_trpc/client';
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
@@ -8,6 +7,7 @@ import {
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from '@/components/ui/carousel';
|
||||
import type { RouterOutputs } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { round } from '@/utils/math';
|
||||
import { ArrowRight, ArrowRightIcon } from 'lucide-react';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import type { RouterOutputs } from '@/app/_trpc/client';
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import type { RouterOutputs } from '@/trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
import type { IChartInput } from '@openpanel/validation';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { useDispatch } from '@/redux';
|
||||
import { api } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { DatabaseIcon } from 'lucide-react';
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { ColorSquare } from '@/components/color-square';
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { useDispatch, useSelector } from '@/redux';
|
||||
import { api } from '@/trpc/client';
|
||||
import { SplitIcon } from 'lucide-react';
|
||||
|
||||
import type { IChartBreakdown } from '@openpanel/validation';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { ColorSquare } from '@/components/color-square';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
|
||||
@@ -7,6 +6,7 @@ import { RenderDots } from '@/components/ui/RenderDots';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { useMappings } from '@/hooks/useMappings';
|
||||
import { useDispatch } from '@/redux';
|
||||
import { api } from '@/trpc/client';
|
||||
import { SlidersHorizontal, Trash } from 'lucide-react';
|
||||
|
||||
import { operators } from '@openpanel/constants';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { useDispatch } from '@/redux';
|
||||
import { api } from '@/trpc/client';
|
||||
import { FilterIcon } from 'lucide-react';
|
||||
|
||||
import type { IChartEvent } from '@openpanel/validation';
|
||||
|
||||
@@ -35,12 +35,14 @@ Alert.displayName = 'Alert';
|
||||
const AlertTitle = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn('mb-1 font-medium leading-none tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
{children}
|
||||
</h5>
|
||||
));
|
||||
AlertTitle.displayName = 'AlertTitle';
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { cn } from '@/utils/cn';
|
||||
import * as TogglePrimitive from '@radix-ui/react-toggle';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
import { cva } from 'class-variance-authority';
|
||||
import type { VariantProps } from 'class-variance-authority';
|
||||
|
||||
const toggleVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
export function useEventNames(projectId: string) {
|
||||
const query = api.chart.events.useQuery({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
export function useEventProperties(projectId: string, event?: string) {
|
||||
const query = api.chart.properties.useQuery({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
export function useEventValues(
|
||||
projectId: string,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
export function useProfileProperties(projectId: string) {
|
||||
const query = api.profile.properties.useQuery({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
import { api } from '@/trpc/client';
|
||||
|
||||
export function useProfileValues(projectId: string, property: string) {
|
||||
const query = api.profile.values.useQuery({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import type { IChartData, IChartSerieDataItem } from '@/app/_trpc/client';
|
||||
import type { IChartData, IChartSerieDataItem } from '@/trpc/client';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
|
||||
export type IRechartPayloadItem = IChartSerieDataItem & { color: string };
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
|
||||
export type IVisibleSeries = ReturnType<typeof useVisibleSeries>['series'];
|
||||
export function useVisibleSeries(data: IChartData, limit?: number | undefined) {
|
||||
|
||||
@@ -1,714 +0,0 @@
|
||||
{
|
||||
"v": "5.5.8",
|
||||
"fr": 50,
|
||||
"ip": 0,
|
||||
"op": 147,
|
||||
"w": 800,
|
||||
"h": 600,
|
||||
"nm": "Paperplane",
|
||||
"ddd": 0,
|
||||
"assets": [
|
||||
{
|
||||
"id": "comp_0",
|
||||
"layers": [
|
||||
{
|
||||
"ddd": 0,
|
||||
"ind": 1,
|
||||
"ty": 4,
|
||||
"nm": "planete Outlines - Group 4",
|
||||
"sr": 1,
|
||||
"ks": {
|
||||
"o": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.833], "y": [0.833] },
|
||||
"o": { "x": [0.167], "y": [0.167] },
|
||||
"t": 0,
|
||||
"s": [0]
|
||||
},
|
||||
{
|
||||
"i": { "x": [0.833], "y": [0.833] },
|
||||
"o": { "x": [0.167], "y": [0.167] },
|
||||
"t": 38,
|
||||
"s": [50]
|
||||
},
|
||||
{
|
||||
"i": { "x": [0.833], "y": [0.833] },
|
||||
"o": { "x": [0.167], "y": [0.167] },
|
||||
"t": 88,
|
||||
"s": [50]
|
||||
},
|
||||
{ "t": 120, "s": [0] }
|
||||
],
|
||||
"ix": 11
|
||||
},
|
||||
"r": { "a": 0, "k": 0, "ix": 10 },
|
||||
"p": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": 0.833, "y": 0.833 },
|
||||
"o": { "x": 0.167, "y": 0.167 },
|
||||
"t": 0,
|
||||
"s": [468.336, 323.378, 0],
|
||||
"to": [-29, 0, 0],
|
||||
"ti": [29, 0, 0]
|
||||
},
|
||||
{ "t": 102, "s": [294.336, 323.378, 0] }
|
||||
],
|
||||
"ix": 2
|
||||
},
|
||||
"a": { "a": 0, "k": [453.672, 304.756, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [50, 50, 100], "ix": 6 }
|
||||
},
|
||||
"ao": 0,
|
||||
"shapes": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[6.742, 0],
|
||||
[0.741, -0.14],
|
||||
[0, 0.074],
|
||||
[13.484, 0],
|
||||
[1.669, -0.361],
|
||||
[19.79, 0],
|
||||
[3.317, -19.082],
|
||||
[2.691, 0],
|
||||
[0, -13.484],
|
||||
[-0.048, -0.629],
|
||||
[2.405, 0],
|
||||
[0, -6.742],
|
||||
[-6.742, 0],
|
||||
[0, 0],
|
||||
[0, 6.743]
|
||||
],
|
||||
"o": [
|
||||
[-0.781, 0],
|
||||
[0.001, -0.074],
|
||||
[0, -13.484],
|
||||
[-1.778, 0],
|
||||
[-3.594, -18.742],
|
||||
[-20.03, 0],
|
||||
[-2.421, -0.804],
|
||||
[-13.485, 0],
|
||||
[0, 0.642],
|
||||
[-1.89, -1.199],
|
||||
[-6.742, 0],
|
||||
[0, 6.743],
|
||||
[0, 0],
|
||||
[6.742, 0],
|
||||
[0, -6.742]
|
||||
],
|
||||
"v": [
|
||||
[75.134, 16.175],
|
||||
[72.85, 16.396],
|
||||
[72.856, 16.175],
|
||||
[48.44, -8.241],
|
||||
[43.262, -7.685],
|
||||
[3.406, -40.591],
|
||||
[-36.571, -6.995],
|
||||
[-44.269, -8.241],
|
||||
[-68.685, 16.175],
|
||||
[-68.604, 18.079],
|
||||
[-75.133, 16.175],
|
||||
[-87.341, 28.383],
|
||||
[-75.133, 40.592],
|
||||
[75.134, 40.592],
|
||||
[87.342, 28.383]
|
||||
],
|
||||
"c": true
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.815686334348, 0.823529471603, 0.827451040231, 1],
|
||||
"ix": 4
|
||||
},
|
||||
"o": { "a": 0, "k": 100, "ix": 5 },
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [453.672, 304.756], "ix": 2 },
|
||||
"a": { "a": 0, "k": [0, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Group 4",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
}
|
||||
],
|
||||
"ip": 0,
|
||||
"op": 151,
|
||||
"st": 0,
|
||||
"bm": 0
|
||||
},
|
||||
{
|
||||
"ddd": 0,
|
||||
"ind": 2,
|
||||
"ty": 4,
|
||||
"nm": "Merged Shape Layer",
|
||||
"sr": 1,
|
||||
"ks": {
|
||||
"o": { "a": 0, "k": 100, "ix": 11 },
|
||||
"r": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.667], "y": [1] },
|
||||
"o": { "x": [0.547], "y": [0] },
|
||||
"t": 0,
|
||||
"s": [0]
|
||||
},
|
||||
{
|
||||
"i": { "x": [0.845], "y": [1] },
|
||||
"o": { "x": [0.333], "y": [0] },
|
||||
"t": 77,
|
||||
"s": [35]
|
||||
},
|
||||
{ "t": 150, "s": [0] }
|
||||
],
|
||||
"ix": 10
|
||||
},
|
||||
"p": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": 0.667, "y": 1 },
|
||||
"o": { "x": 0.333, "y": 0 },
|
||||
"t": 0,
|
||||
"s": [390.319, 298.2, 0],
|
||||
"to": [0, -2.583, 0],
|
||||
"ti": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"i": { "x": 0.667, "y": 1 },
|
||||
"o": { "x": 0.333, "y": 0 },
|
||||
"t": 44,
|
||||
"s": [390.319, 282.7, 0],
|
||||
"to": [0, 0, 0],
|
||||
"ti": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"i": { "x": 0.667, "y": 1 },
|
||||
"o": { "x": 0.333, "y": 0 },
|
||||
"t": 110,
|
||||
"s": [390.319, 319.25, 0],
|
||||
"to": [0, 0, 0],
|
||||
"ti": [0, 0, 0]
|
||||
},
|
||||
{ "t": 150, "s": [390.319, 298.2, 0] }
|
||||
],
|
||||
"ix": 2
|
||||
},
|
||||
"a": { "a": 0, "k": [664.319, 256.2, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100, 100], "ix": 6 }
|
||||
},
|
||||
"ao": 0,
|
||||
"shapes": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"o": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"v": [
|
||||
[18.967, -3.189],
|
||||
[-18.967, 19.935],
|
||||
[-0.949, -19.935]
|
||||
],
|
||||
"c": true
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [
|
||||
0.223528981209, 0.192156970501, 0.674510002136, 1
|
||||
],
|
||||
"ix": 4
|
||||
},
|
||||
"o": { "a": 0, "k": 100, "ix": 5 },
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [236.879, 292.737], "ix": 2 },
|
||||
"a": { "a": 0, "k": [0, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Group 1",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [633.939, 275.369], "ix": 2 },
|
||||
"a": { "a": 0, "k": [236.879, 292.737], "ix": 1 },
|
||||
"s": { "a": 0, "k": [50, 50], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "planete Outlines - Group 1",
|
||||
"np": 1,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"o": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"v": [
|
||||
[-98.335, 64.79],
|
||||
[-105.619, 4.984],
|
||||
[105.619, -64.79],
|
||||
[-80.316, 24.919]
|
||||
],
|
||||
"c": true
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [
|
||||
0.278430998325, 0.294117987156, 0.847059011459, 1
|
||||
],
|
||||
"ix": 4
|
||||
},
|
||||
"o": { "a": 0, "k": 100, "ix": 5 },
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [316.247, 247.882], "ix": 2 },
|
||||
"a": { "a": 0, "k": [0, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Group 2",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [673.623, 252.941], "ix": 2 },
|
||||
"a": { "a": 0, "k": [316.247, 247.882], "ix": 1 },
|
||||
"s": { "a": 0, "k": [50, 50], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "planete Outlines - Group 2",
|
||||
"np": 1,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 2,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"o": [
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0]
|
||||
],
|
||||
"v": [
|
||||
[-133.812, -42.171],
|
||||
[133.812, -75.141],
|
||||
[5.765, 75.141],
|
||||
[-61.708, 18.402],
|
||||
[124.227, -71.307],
|
||||
[-87.011, -1.534]
|
||||
],
|
||||
"c": true
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [
|
||||
0.365000009537, 0.407999992371, 0.976000010967, 1
|
||||
],
|
||||
"ix": 4
|
||||
},
|
||||
"o": { "a": 0, "k": 100, "ix": 5 },
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [297.638, 254.4], "ix": 2 },
|
||||
"a": { "a": 0, "k": [0, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Group 3",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [664.319, 256.2], "ix": 2 },
|
||||
"a": { "a": 0, "k": [297.638, 254.4], "ix": 1 },
|
||||
"s": { "a": 0, "k": [50, 50], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "planete Outlines - Group 3",
|
||||
"np": 1,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 3,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
}
|
||||
],
|
||||
"ip": 0,
|
||||
"op": 151,
|
||||
"st": 0,
|
||||
"bm": 0
|
||||
},
|
||||
{
|
||||
"ddd": 0,
|
||||
"ind": 3,
|
||||
"ty": 4,
|
||||
"nm": "planete Outlines - Group 5",
|
||||
"sr": 1,
|
||||
"ks": {
|
||||
"o": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": [0.667], "y": [1] },
|
||||
"o": { "x": [0.333], "y": [0] },
|
||||
"t": 0,
|
||||
"s": [0]
|
||||
},
|
||||
{
|
||||
"i": { "x": [0.667], "y": [1] },
|
||||
"o": { "x": [0.333], "y": [0] },
|
||||
"t": 45,
|
||||
"s": [100]
|
||||
},
|
||||
{
|
||||
"i": { "x": [0.667], "y": [1] },
|
||||
"o": { "x": [0.333], "y": [0] },
|
||||
"t": 102,
|
||||
"s": [100]
|
||||
},
|
||||
{ "t": 150, "s": [0] }
|
||||
],
|
||||
"ix": 11
|
||||
},
|
||||
"r": { "a": 0, "k": 0, "ix": 10 },
|
||||
"p": {
|
||||
"a": 1,
|
||||
"k": [
|
||||
{
|
||||
"i": { "x": 0.833, "y": 0.833 },
|
||||
"o": { "x": 0.167, "y": 0.167 },
|
||||
"t": 0,
|
||||
"s": [327.38, 267.583, 0],
|
||||
"to": [25.833, 0, 0],
|
||||
"ti": [-25.833, 0, 0]
|
||||
},
|
||||
{ "t": 150, "s": [482.38, 267.583, 0] }
|
||||
],
|
||||
"ix": 2
|
||||
},
|
||||
"a": { "a": 0, "k": [171.76, 193.166, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [50, 50, 100], "ix": 6 }
|
||||
},
|
||||
"ao": 0,
|
||||
"shapes": [
|
||||
{
|
||||
"ty": "gr",
|
||||
"it": [
|
||||
{
|
||||
"ind": 0,
|
||||
"ty": "sh",
|
||||
"ix": 1,
|
||||
"ks": {
|
||||
"a": 0,
|
||||
"k": {
|
||||
"i": [
|
||||
[13.485, 0],
|
||||
[4.38, -4.171],
|
||||
[21.913, 0],
|
||||
[3.575, -18.765],
|
||||
[1.851, 0],
|
||||
[0, -13.484],
|
||||
[-0.011, -0.291],
|
||||
[1.599, 0],
|
||||
[0, -6.743],
|
||||
[-6.742, 0],
|
||||
[0, 0],
|
||||
[0, 13.485]
|
||||
],
|
||||
"o": [
|
||||
[-6.526, 0],
|
||||
[-0.793, -21.719],
|
||||
[-19.806, 0],
|
||||
[-1.734, -0.391],
|
||||
[-13.485, 0],
|
||||
[0, 0.293],
|
||||
[-1.4, -0.559],
|
||||
[-6.742, 0],
|
||||
[0, 6.742],
|
||||
[0, 0],
|
||||
[13.485, 0],
|
||||
[0, -13.484]
|
||||
],
|
||||
"v": [
|
||||
[59.669, -8.242],
|
||||
[42.84, -1.506],
|
||||
[2.287, -40.592],
|
||||
[-37.576, -7.638],
|
||||
[-42.962, -8.242],
|
||||
[-67.378, 16.174],
|
||||
[-67.356, 17.049],
|
||||
[-71.878, 16.174],
|
||||
[-84.086, 28.383],
|
||||
[-71.878, 40.591],
|
||||
[59.669, 40.591],
|
||||
[84.086, 16.174]
|
||||
],
|
||||
"c": true
|
||||
},
|
||||
"ix": 2
|
||||
},
|
||||
"nm": "Path 1",
|
||||
"mn": "ADBE Vector Shape - Group",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "fl",
|
||||
"c": {
|
||||
"a": 0,
|
||||
"k": [0.816000007181, 0.823999980852, 0.827000038297, 1],
|
||||
"ix": 4
|
||||
},
|
||||
"o": { "a": 0, "k": 100, "ix": 5 },
|
||||
"r": 1,
|
||||
"bm": 0,
|
||||
"nm": "Fill 1",
|
||||
"mn": "ADBE Vector Graphic - Fill",
|
||||
"hd": false
|
||||
},
|
||||
{
|
||||
"ty": "tr",
|
||||
"p": { "a": 0, "k": [171.76, 193.166], "ix": 2 },
|
||||
"a": { "a": 0, "k": [0, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [100, 100], "ix": 3 },
|
||||
"r": { "a": 0, "k": 0, "ix": 6 },
|
||||
"o": { "a": 0, "k": 100, "ix": 7 },
|
||||
"sk": { "a": 0, "k": 0, "ix": 4 },
|
||||
"sa": { "a": 0, "k": 0, "ix": 5 },
|
||||
"nm": "Transform"
|
||||
}
|
||||
],
|
||||
"nm": "Group 5",
|
||||
"np": 2,
|
||||
"cix": 2,
|
||||
"bm": 0,
|
||||
"ix": 1,
|
||||
"mn": "ADBE Vector Group",
|
||||
"hd": false
|
||||
}
|
||||
],
|
||||
"ip": 0,
|
||||
"op": 151,
|
||||
"st": 0,
|
||||
"bm": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"ddd": 0,
|
||||
"ind": 1,
|
||||
"ty": 0,
|
||||
"nm": "Pre-comp 1",
|
||||
"refId": "comp_0",
|
||||
"sr": 1,
|
||||
"ks": {
|
||||
"o": { "a": 0, "k": 100, "ix": 11 },
|
||||
"r": { "a": 0, "k": 0, "ix": 10 },
|
||||
"p": { "a": 0, "k": [406, 306, 0], "ix": 2 },
|
||||
"a": { "a": 0, "k": [400, 300, 0], "ix": 1 },
|
||||
"s": { "a": 0, "k": [179, 179, 100], "ix": 6 }
|
||||
},
|
||||
"ao": 0,
|
||||
"w": 800,
|
||||
"h": 600,
|
||||
"ip": 0,
|
||||
"op": 147,
|
||||
"st": 0,
|
||||
"bm": 0
|
||||
}
|
||||
],
|
||||
"markers": []
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { CreateClientSuccess } from '@/components/clients/create-client-success';
|
||||
import { Button, buttonVariants } from '@/components/ui/button';
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
@@ -9,6 +8,7 @@ import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { SaveIcon, WallpaperIcon } from 'lucide-react';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { api, handleError } from '@/app/_trpc/client';
|
||||
import { ButtonContainer } from '@/components/button-container';
|
||||
import { InputWithLabel } from '@/components/forms/input-with-label';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { api, handleError } from '@/trpc/client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter } from '@/server/api/trpc';
|
||||
import { createTRPCRouter } from '@/trpc/api/trpc';
|
||||
|
||||
import { chartRouter } from './routers/chart';
|
||||
import { clientRouter } from './routers/client';
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
publicProcedure,
|
||||
} from '@/server/api/trpc';
|
||||
} from '@/trpc/api/trpc';
|
||||
import { average, max, min, round, sum } from '@/utils/math';
|
||||
import { flatten, map, pipe, prop, sort, uniq } from 'ramda';
|
||||
import { z } from 'zod';
|
||||
@@ -1,5 +1,5 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { hashPassword, stripTrailingSlash } from '@openpanel/common';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { getId } from '@/utils/getDbId';
|
||||
import { PrismaError } from 'prisma-error-enum';
|
||||
import { z } from 'zod';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db } from '@openpanel/db';
|
||||
@@ -1,5 +1,5 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { clerkClient } from '@clerk/nextjs';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { clerkClient } from '@clerk/nextjs';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
publicProcedure,
|
||||
} from '@/server/api/trpc';
|
||||
} from '@/trpc/api/trpc';
|
||||
import { flatten, map, pipe, prop, sort, uniq } from 'ramda';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { getId } from '@/utils/getDbId';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
publicProcedure,
|
||||
} from '@/server/api/trpc';
|
||||
} from '@/trpc/api/trpc';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db, getReferences } from '@openpanel/db';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db } from '@openpanel/db';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
|
||||
import { db } from '@openpanel/db';
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/trpc/api/trpc';
|
||||
import { clerkClient } from '@clerk/nextjs';
|
||||
import { z } from 'zod';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AppRouter } from '@/server/api/root';
|
||||
import type { AppRouter } from '@/trpc/api/root';
|
||||
import type { TRPCClientErrorBase } from '@trpc/react-query';
|
||||
import { createTRPCReact } from '@trpc/react-query';
|
||||
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
|
||||
@@ -6,7 +6,7 @@ export function DeviceIdWarning() {
|
||||
<Callout>
|
||||
Read more about{' '}
|
||||
<Link href="/docs/device-id">device id and why you might want it</Link>.
|
||||
**We recommend not to but it's up to you.**
|
||||
**We recommend not to but it's up to you.**
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,5 +17,6 @@
|
||||
"title": "Others"
|
||||
},
|
||||
"javascript": "Javascript SDK",
|
||||
"web": "Web SDK"
|
||||
"web": "Web SDK",
|
||||
"api": "API"
|
||||
}
|
||||
|
||||
@@ -41,9 +41,9 @@ export default function Page() {
|
||||
<p>
|
||||
<strong>Affiliate</strong> means an entity that controls, is
|
||||
controlled by or is under common control with a party, where
|
||||
"control" means ownership of 50% or more of the shares, equity
|
||||
interest or other securities entitled to vote for election of
|
||||
directors or other managing authority.
|
||||
"control" means ownership of 50% or more of the shares,
|
||||
equity interest or other securities entitled to vote for election
|
||||
of directors or other managing authority.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
@@ -54,9 +54,10 @@ export default function Page() {
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
<strong>Company</strong> (referred to as either "the Company",
|
||||
"We", "Us" or "Our" in this Agreement) refers to Coderax AB, Sankt
|
||||
Eriksgatan 100, 113 31, Stockholm.
|
||||
<strong>Company</strong> (referred to as either "the
|
||||
Company", "We", "Us" or "Our"
|
||||
in this Agreement) refers to Coderax AB, Sankt Eriksgatan 100, 113
|
||||
31, Stockholm.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
@@ -151,7 +152,7 @@ export default function Page() {
|
||||
<h4>Usage Data</h4>
|
||||
<p>Usage Data is collected automatically when using the Service.</p>
|
||||
<p>
|
||||
Usage Data may include information such as Your Device's Internet
|
||||
Usage Data may include information such as Your Device's Internet
|
||||
Protocol address (e.g. IP address), browser type, browser version, the
|
||||
pages of our Service that You visit, the time and date of Your visit,
|
||||
the time spent on those pages, unique device identifiers and other
|
||||
@@ -198,10 +199,10 @@ export default function Page() {
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies
|
||||
remain on Your personal computer or mobile device when You go offline,
|
||||
while Session Cookies are deleted as soon as You close Your web
|
||||
browser. You can learn more about cookies{' '}
|
||||
Cookies can be "Persistent" or "Session" Cookies.
|
||||
Persistent Cookies remain on Your personal computer or mobile device
|
||||
when You go offline, while Session Cookies are deleted as soon as You
|
||||
close Your web browser. You can learn more about cookies{' '}
|
||||
<a
|
||||
href="https://www.termsfeed.com/blog/cookies/#What_Are_Cookies"
|
||||
target="_blank"
|
||||
@@ -291,11 +292,11 @@ export default function Page() {
|
||||
<p>
|
||||
<strong>To contact You:</strong> To contact You by email,
|
||||
telephone calls, SMS, or other equivalent forms of electronic
|
||||
communication, such as a mobile application's push notifications
|
||||
regarding updates or informative communications related to the
|
||||
functionalities, products or contracted services, including the
|
||||
security updates, when necessary or reasonable for their
|
||||
implementation.
|
||||
communication, such as a mobile application's push
|
||||
notifications regarding updates or informative communications
|
||||
related to the functionalities, products or contracted services,
|
||||
including the security updates, when necessary or reasonable for
|
||||
their implementation.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
@@ -391,12 +392,12 @@ export default function Page() {
|
||||
<h3>Transfer of Your Personal Data</h3>
|
||||
<p>
|
||||
Your information, including Personal Data, is processed at the
|
||||
Company's operating offices and in any other places where the parties
|
||||
involved in the processing are located. It means that this information
|
||||
may be transferred to — and maintained on — computers located outside
|
||||
of Your state, province, country or other governmental jurisdiction
|
||||
where the data protection laws may differ than those from Your
|
||||
jurisdiction.
|
||||
Company's operating offices and in any other places where the
|
||||
parties involved in the processing are located. It means that this
|
||||
information may be transferred to — and maintained on — computers
|
||||
located outside of Your state, province, country or other governmental
|
||||
jurisdiction where the data protection laws may differ than those from
|
||||
Your jurisdiction.
|
||||
</p>
|
||||
<p>
|
||||
Your consent to this Privacy Policy followed by Your submission of
|
||||
@@ -468,7 +469,7 @@ export default function Page() {
|
||||
acceptable means to protect Your Personal Data, We cannot guarantee
|
||||
its absolute security.
|
||||
</p>
|
||||
<h2>Children's Privacy</h2>
|
||||
<h2>Children's Privacy</h2>
|
||||
<p>
|
||||
Our Service does not address anyone under the age of 13. We do not
|
||||
knowingly collect personally identifiable information from anyone
|
||||
@@ -481,15 +482,15 @@ export default function Page() {
|
||||
<p>
|
||||
If We need to rely on consent as a legal basis for processing Your
|
||||
information and Your country requires consent from a parent, We may
|
||||
require Your parent's consent before We collect and use that
|
||||
require Your parent's consent before We collect and use that
|
||||
information.
|
||||
</p>
|
||||
<h2>Links to Other Websites</h2>
|
||||
<p>
|
||||
Our Service may contain links to other websites that are not operated
|
||||
by Us. If You click on a third party link, You will be directed to
|
||||
that third party's site. We strongly advise You to review the Privacy
|
||||
Policy of every site You visit.
|
||||
that third party's site. We strongly advise You to review the
|
||||
Privacy Policy of every site You visit.
|
||||
</p>
|
||||
<p>
|
||||
We have no control over and assume no responsibility for the content,
|
||||
@@ -502,8 +503,8 @@ export default function Page() {
|
||||
</p>
|
||||
<p>
|
||||
We will let You know via email and/or a prominent notice on Our
|
||||
Service, prior to the change becoming effective and update the "Last
|
||||
updated" date at the top of this Privacy Policy.
|
||||
Service, prior to the change becoming effective and update the
|
||||
"Last updated" date at the top of this Privacy Policy.
|
||||
</p>
|
||||
<p>
|
||||
You are advised to review this Privacy Policy periodically for any
|
||||
|
||||
@@ -313,7 +313,7 @@ export default function Page() {
|
||||
of the Company and any of its suppliers under any provision of this
|
||||
Terms and Your exclusive remedy for all of the foregoing shall be
|
||||
limited to the amount actually paid by You through the Service or 100
|
||||
USD if You haven't purchased anything through the Service.
|
||||
USD if You haven't purchased anything through the Service.
|
||||
</p>
|
||||
<p>
|
||||
To the maximum extent permitted by applicable law, in no event shall
|
||||
@@ -332,8 +332,8 @@ export default function Page() {
|
||||
Some states do not allow the exclusion of implied warranties or
|
||||
limitation of liability for incidental or consequential damages, which
|
||||
means that some of the above limitations may not apply. In these
|
||||
states, each party's liability will be limited to the greatest extent
|
||||
permitted by law.
|
||||
states, each party's liability will be limited to the greatest
|
||||
extent permitted by law.
|
||||
</p>
|
||||
<h2>"AS IS" and "AS AVAILABLE" Disclaimer</h2>
|
||||
<p>
|
||||
@@ -357,9 +357,9 @@ export default function Page() {
|
||||
</p>
|
||||
<p>
|
||||
Without limiting the foregoing, neither the Company nor any of the
|
||||
company's provider makes any representation or warranty of any kind,
|
||||
express or implied: (i) as to the operation or availability of the
|
||||
Service, or the information, content, and materials or products
|
||||
company's provider makes any representation or warranty of any
|
||||
kind, express or implied: (i) as to the operation or availability of
|
||||
the Service, or the information, content, and materials or products
|
||||
included thereon; (ii) that the Service will be uninterrupted or
|
||||
error-free; (iii) as to the accuracy, reliability, or currency of any
|
||||
information or content provided through the Service; or (iv) that the
|
||||
@@ -420,7 +420,7 @@ export default function Page() {
|
||||
<p>
|
||||
Except as provided herein, the failure to exercise a right or to
|
||||
require performance of an obligation under these Terms shall not
|
||||
affect a party's ability to exercise such right or require such
|
||||
affect a party's ability to exercise such right or require such
|
||||
performance at any time thereafter nor shall the waiver of a breach
|
||||
constitute a waiver of any subsequent breach.
|
||||
</p>
|
||||
@@ -434,9 +434,9 @@ export default function Page() {
|
||||
<p>
|
||||
We reserve the right, at Our sole discretion, to modify or replace
|
||||
these Terms at any time. If a revision is material We will make
|
||||
reasonable efforts to provide at least 30 days' notice prior to any
|
||||
new terms taking effect. What constitutes a material change will be
|
||||
determined at Our sole discretion.
|
||||
reasonable efforts to provide at least 30 days' notice prior to
|
||||
any new terms taking effect. What constitutes a material change will
|
||||
be determined at Our sole discretion.
|
||||
</p>
|
||||
<p>
|
||||
By continuing to access or use Our Service after those revisions
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function POST(req: Request) {
|
||||
|
||||
await db.waitlist.create({
|
||||
data: {
|
||||
email: body.email.toLowerCase(),
|
||||
email: String(body.email).toLowerCase(),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ const features: FeatureItem[] = [
|
||||
description: (
|
||||
<>
|
||||
<p>
|
||||
Deep dive into your user's behavior and understand how they interact
|
||||
with your app/website.
|
||||
Deep dive into your user's behavior and understand how they
|
||||
interact with your app/website.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
|
||||
@@ -34,8 +34,8 @@ export function JoinWaitlistHero({ className }: JoinWaitlistProps) {
|
||||
<DialogHeader>
|
||||
<DialogTitle>Thanks so much!</DialogTitle>
|
||||
<DialogDescription>
|
||||
You're now on the waiting list. We'll let you know when we're
|
||||
ready. Should be within a month or two 🚀
|
||||
You're now on the waiting list. We'll let you know when
|
||||
we're ready. Should be within a month or two 🚀
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ export function JoinWaitlist({ className }: JoinWaitlistProps) {
|
||||
<DialogHeader>
|
||||
<DialogTitle>Thanks so much!</DialogTitle>
|
||||
<DialogDescription>
|
||||
You're now on the waiting list. We'll let you know when we're
|
||||
ready. Should be within a month or two 🚀
|
||||
You're now on the waiting list. We'll let you know when
|
||||
we're ready. Should be within a month or two 🚀
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
|
||||
@@ -57,14 +57,15 @@ export default function Page() {
|
||||
<h3 className="text-blue-dark text-lg font-bold">TL;DR</h3>
|
||||
<Paragraph>
|
||||
Our open-source analytic library fills a crucial gap by combining
|
||||
the strengths of Mixpanel's powerful features with Plausible's
|
||||
clear overview page. Motivated by the lack of an open-source
|
||||
alternative to Mixpanel and inspired by Plausible's simplicity, we
|
||||
aim to create an intuitive platform with predictable pricing. With
|
||||
a single-tier pricing model and limits only on monthly event
|
||||
counts, our goal is to democratize analytics, offering
|
||||
unrestricted access to all features while ensuring affordability
|
||||
and transparency for users of all project sizes.
|
||||
the strengths of Mixpanel's powerful features with
|
||||
Plausible's clear overview page. Motivated by the lack of an
|
||||
open-source alternative to Mixpanel and inspired by
|
||||
Plausible's simplicity, we aim to create an intuitive
|
||||
platform with predictable pricing. With a single-tier pricing
|
||||
model and limits only on monthly event counts, our goal is to
|
||||
democratize analytics, offering unrestricted access to all
|
||||
features while ensuring affordability and transparency for users
|
||||
of all project sizes.
|
||||
</Paragraph>
|
||||
|
||||
<h3 className="text-blue-dark mt-12 text-lg font-bold">The why</h3>
|
||||
@@ -72,10 +73,10 @@ export default function Page() {
|
||||
Our open-source analytic library emerged from a clear need within
|
||||
the analytics community. While platforms like Mixpanel offer
|
||||
powerful and user-friendly features, they lack a comprehensive
|
||||
overview page akin to Plausible's, which succinctly summarizes
|
||||
essential metrics. Recognizing this gap, we saw an opportunity to
|
||||
combine the strengths of both platforms while addressing their
|
||||
respective shortcomings.
|
||||
overview page akin to Plausible's, which succinctly
|
||||
summarizes essential metrics. Recognizing this gap, we saw an
|
||||
opportunity to combine the strengths of both platforms while
|
||||
addressing their respective shortcomings.
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph>
|
||||
@@ -87,7 +88,7 @@ export default function Page() {
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph>
|
||||
Inspired by Plausible's exemplary approach to simplicity and
|
||||
Inspired by Plausible's exemplary approach to simplicity and
|
||||
clarity, we aim to build upon their foundation and further refine
|
||||
the user experience. By harnessing the best practices demonstrated
|
||||
by Plausible, we aspire to create an intuitive and streamlined
|
||||
@@ -108,12 +109,13 @@ export default function Page() {
|
||||
<Paragraph>
|
||||
In line with our commitment to fairness and accessibility, our
|
||||
pricing model will only impose limits on the number of events
|
||||
users can send each month. This approach, akin to Plausible's,
|
||||
ensures that users have the freedom to explore and utilize our
|
||||
platform to its fullest potential without arbitrary restrictions
|
||||
on reports or user counts. Ultimately, our goal is to democratize
|
||||
analytics by offering a reliable, transparent, and cost-effective
|
||||
solution for projects of all sizes.
|
||||
users can send each month. This approach, akin to
|
||||
Plausible's, ensures that users have the freedom to explore
|
||||
and utilize our platform to its fullest potential without
|
||||
arbitrary restrictions on reports or user counts. Ultimately, our
|
||||
goal is to democratize analytics by offering a reliable,
|
||||
transparent, and cost-effective solution for projects of all
|
||||
sizes.
|
||||
</Paragraph>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,8 +19,9 @@ const items = [
|
||||
title: 'Own Your Own Data',
|
||||
description: (
|
||||
<p>
|
||||
We believe that you should own your own data. That's why we don't sell
|
||||
your data to third parties. <strong>Ever. Period.</strong>
|
||||
We believe that you should own your own data. That's why we
|
||||
don't sell your data to third parties.{' '}
|
||||
<strong>Ever. Period.</strong>
|
||||
</p>
|
||||
),
|
||||
icon: KeyIcon,
|
||||
|
||||
@@ -89,11 +89,16 @@ export interface ALinkProps
|
||||
extends React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
||||
VariantProps<typeof buttonVariants> {}
|
||||
|
||||
export const ALink = ({ variant, size, className, ...props }: ALinkProps) => {
|
||||
export const ALink = ({
|
||||
variant,
|
||||
size,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: ALinkProps) => {
|
||||
return (
|
||||
<a
|
||||
{...props}
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
/>
|
||||
<a {...props} className={cn(buttonVariants({ variant, size, className }))}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [".", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "public"]
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
# Create T3 App
|
||||
|
||||
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.
|
||||
|
||||
## What's next? How do I make an app with this?
|
||||
|
||||
We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.
|
||||
|
||||
If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.
|
||||
|
||||
- [Next.js](https://nextjs.org)
|
||||
- [NextAuth.js](https://next-auth.js.org)
|
||||
- [Prisma](https://prisma.io)
|
||||
- [Tailwind CSS](https://tailwindcss.com)
|
||||
- [tRPC](https://trpc.io)
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
|
||||
|
||||
- [Documentation](https://create.t3.gg/)
|
||||
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials
|
||||
|
||||
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
|
||||
|
||||
## How do I deploy this?
|
||||
|
||||
Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.
|
||||
6
apps/test/next-env.d.ts
vendored
6
apps/test/next-env.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference types="next/navigation-types/compat/navigation" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
|
||||
* for Docker builds.
|
||||
*/
|
||||
|
||||
/** @type {import("next").NextConfig} */
|
||||
const config = {
|
||||
reactStrictMode: false,
|
||||
transpilePackages: ['@openpanel/sdk', '@openpanel/web', '@openpanel/nextjs'],
|
||||
eslint: { ignoreDuringBuilds: true },
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
/**
|
||||
* If you are using `appDir` then you must comment the below `i18n` config out.
|
||||
*
|
||||
* @see https://github.com/vercel/next.js/issues/41980
|
||||
*/
|
||||
i18n: {
|
||||
locales: ['en'],
|
||||
defaultLocale: 'en',
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user