diff --git a/apps/web/package.json b/apps/web/package.json
index 8142b4ec..b58777d9 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -52,6 +52,7 @@
"cmdk": "^0.2.1",
"date-fns": "^3.3.1",
"embla-carousel-react": "8.0.0-rc22",
+ "flag-icons": "^7.1.0",
"hamburger-react": "^2.5.0",
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
diff --git a/apps/web/src/app/(app)/[organizationId]/[projectId]/create-client.tsx b/apps/web/src/app/(app)/[organizationId]/[projectId]/create-client.tsx
index 84b1b53d..71757a87 100644
--- a/apps/web/src/app/(app)/[organizationId]/[projectId]/create-client.tsx
+++ b/apps/web/src/app/(app)/[organizationId]/[projectId]/create-client.tsx
@@ -2,7 +2,7 @@
import { useEffect, useState } from 'react';
import { Button } from '@/components/ui/button';
-import { Checkbox, CheckboxInput } from '@/components/ui/checkbox';
+import { CheckboxInput } from '@/components/ui/checkbox';
import {
Dialog,
DialogContent,
diff --git a/apps/web/src/app/(app)/[organizationId]/[projectId]/events/event-list-item.tsx b/apps/web/src/app/(app)/[organizationId]/[projectId]/events/event-list-item.tsx
index cea0a06b..6cf3d545 100644
--- a/apps/web/src/app/(app)/[organizationId]/[projectId]/events/event-list-item.tsx
+++ b/apps/web/src/app/(app)/[organizationId]/[projectId]/events/event-list-item.tsx
@@ -18,30 +18,31 @@ import { EventIcon } from './event-icon';
type EventListItemProps = IServiceCreateEventPayload;
-export function EventListItem({
- profile,
- createdAt,
- name,
- properties,
- path,
- duration,
- referrer,
- referrerName,
- referrerType,
- brand,
- model,
- browser,
- browserVersion,
- os,
- osVersion,
- city,
- region,
- country,
- continent,
- device,
- projectId,
- meta,
-}: EventListItemProps) {
+export function EventListItem(props: EventListItemProps) {
+ const {
+ profile,
+ createdAt,
+ name,
+ properties,
+ path,
+ duration,
+ referrer,
+ referrerName,
+ referrerType,
+ brand,
+ model,
+ browser,
+ browserVersion,
+ os,
+ osVersion,
+ city,
+ region,
+ country,
+ continent,
+ device,
+ projectId,
+ meta,
+ } = props;
const params = useAppParams();
const [, setEvents] = useEventQueryNamesFilter({ shallow: false });
const [, setFilter] = useEventQueryFilters({ shallow: false });
@@ -168,6 +169,9 @@ export function EventListItem({
content={
<>
+ {profile?.id === props.deviceId && (
+
+ )}
{profile && (
-
-
-
+
);
diff --git a/apps/web/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/list-profile-events.tsx b/apps/web/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/list-profile-events.tsx
deleted file mode 100644
index 6af713dc..00000000
--- a/apps/web/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/list-profile-events.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-'use client';
-
-import { useMemo } from 'react';
-import { api } from '@/app/_trpc/client';
-import { Pagination, usePagination } from '@/components/Pagination';
-import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
-import { useEventNames } from '@/hooks/useEventNames';
-import { parseAsJson, useQueryState } from 'nuqs';
-
-import { EventListItem } from '../../events/event-list-item';
-
-interface ListProfileEvents {
- projectId: string;
- profileId: string;
-}
-
-export default function ListProfileEvents({
- projectId,
- profileId,
-}: ListProfileEvents) {
- const pagination = usePagination(50);
- const [eventFilters, setEventFilters] = useQueryState(
- 'events',
- parseAsJson().withDefault([])
- );
-
- const eventNames = useEventNames(projectId);
- const eventsQuery = api.event.list.useQuery(
- {
- projectId,
- profileId,
- events: eventFilters,
- ...pagination,
- },
- {
- keepPreviousData: true,
- }
- );
- const events = useMemo(() => eventsQuery.data ?? [], [eventsQuery]);
-
- return (
- <>
-
-
-
-
- {events.map((item) => (
-
- ))}
-
-
- >
- );
-}
diff --git a/apps/web/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx b/apps/web/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx
index 60f9f2c3..4b788c46 100644
--- a/apps/web/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx
+++ b/apps/web/src/app/(app)/[organizationId]/[projectId]/profiles/[profileId]/page.tsx
@@ -10,6 +10,7 @@ import {
eventQueryNamesFilter,
} from '@/hooks/useEventQueryFilters';
import { getExists } from '@/server/pageExists';
+import { cn } from '@/utils/cn';
import { getProfileName } from '@/utils/getters';
import { notFound } from 'next/navigation';
import { parseAsInteger, parseAsString } from 'nuqs';
diff --git a/apps/web/src/app/(public)/share/overview/[id]/page.tsx b/apps/web/src/app/(public)/share/overview/[id]/page.tsx
index 0e6ae352..a26dc6e8 100644
--- a/apps/web/src/app/(public)/share/overview/[id]/page.tsx
+++ b/apps/web/src/app/(public)/share/overview/[id]/page.tsx
@@ -7,7 +7,7 @@ import { OverviewFiltersDrawer } from '@/components/overview/filters/overview-fi
import ServerLiveCounter from '@/components/overview/live-counter';
import { OverviewLiveHistogram } from '@/components/overview/overview-live-histogram';
import OverviewTopDevices from '@/components/overview/overview-top-devices';
-import OverviewTopEvents from '@/components/overview/overview-top-events';
+import OverviewTopEvents from '@/components/overview/overview-top-events/overview-top-events';
import OverviewTopGeo from '@/components/overview/overview-top-geo';
import OverviewTopPages from '@/components/overview/overview-top-pages';
import OverviewTopSources from '@/components/overview/overview-top-sources';
diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx
index b157a96e..188ec3b4 100644
--- a/apps/web/src/app/layout.tsx
+++ b/apps/web/src/app/layout.tsx
@@ -3,6 +3,7 @@ import { cn } from '@/utils/cn';
import Providers from './providers';
import '@/styles/globals.css';
+import '/node_modules/flag-icons/css/flag-icons.min.css';
export const metadata = {
title: 'Overview - Openpanel.dev',
diff --git a/apps/web/src/components/overview/overview-top-devices.tsx b/apps/web/src/components/overview/overview-top-devices.tsx
index 95d28009..4d346f25 100644
--- a/apps/web/src/components/overview/overview-top-devices.tsx
+++ b/apps/web/src/components/overview/overview-top-devices.tsx
@@ -191,28 +191,31 @@ export default function OverviewTopDevices({
{
- switch (widget.key) {
- case 'devices':
- setFilter('device', item.name);
- break;
- case 'browser':
- setWidget('browser_version');
- setFilter('browser', item.name);
- break;
- case 'browser_version':
- setFilter('browser_version', item.name);
- break;
- case 'os':
- setWidget('os_version');
- setFilter('os', item.name);
- break;
- case 'os_version':
- setFilter('os_version', item.name);
- break;
- }
+ {...{
+ projectId,
+ startDate,
+ endDate,
+ events: [
+ {
+ segment: 'user',
+ filters,
+ id: 'A',
+ name: 'session_start',
+ },
+ ],
+ breakdowns: [
+ {
+ id: 'A',
+ name: 'browser_version',
+ },
+ ],
+ chartType: 'bar',
+ lineType: 'monotone',
+ interval: interval,
+ name: 'Top sources',
+ range: range,
+ previous: previous,
+ metric: 'sum',
}}
/>
diff --git a/apps/web/src/components/overview/overview-top-events/index.tsx b/apps/web/src/components/overview/overview-top-events/index.tsx
new file mode 100644
index 00000000..f54fa5eb
--- /dev/null
+++ b/apps/web/src/components/overview/overview-top-events/index.tsx
@@ -0,0 +1,16 @@
+import { getConversionEventNames } from '@mixan/db';
+
+import type { OverviewTopEventsProps } from './overview-top-events';
+import OverviewTopEvents from './overview-top-events';
+
+export default async function OverviewTopEventsServer({
+ projectId,
+}: Omit) {
+ const eventNames = await getConversionEventNames(projectId);
+ return (
+ item.name)}
+ />
+ );
+}
diff --git a/apps/web/src/components/overview/overview-top-events.tsx b/apps/web/src/components/overview/overview-top-events/overview-top-events.tsx
similarity index 63%
rename from apps/web/src/components/overview/overview-top-events.tsx
rename to apps/web/src/components/overview/overview-top-events/overview-top-events.tsx
index 1a11d358..0519ba21 100644
--- a/apps/web/src/components/overview/overview-top-events.tsx
+++ b/apps/web/src/components/overview/overview-top-events/overview-top-events.tsx
@@ -4,16 +4,18 @@ import { ChartSwitch } from '@/components/report/chart';
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
import { cn } from '@/utils/cn';
-import { Widget, WidgetBody } from '../Widget';
-import { WidgetButtons, WidgetHead } from './overview-widget';
-import { useOverviewOptions } from './useOverviewOptions';
-import { useOverviewWidget } from './useOverviewWidget';
+import { Widget, WidgetBody } from '../../Widget';
+import { WidgetButtons, WidgetHead } from '../overview-widget';
+import { useOverviewOptions } from '../useOverviewOptions';
+import { useOverviewWidget } from '../useOverviewWidget';
-interface OverviewTopEventsProps {
+export interface OverviewTopEventsProps {
projectId: string;
+ conversions: string[];
}
export default function OverviewTopEvents({
projectId,
+ conversions,
}: OverviewTopEventsProps) {
const { interval, range, previous, startDate, endDate } =
useOverviewOptions();
@@ -57,6 +59,44 @@ export default function OverviewTopEvents({
metric: 'sum',
},
},
+ conversions: {
+ title: 'Conversions',
+ btn: 'Conversions',
+ chart: {
+ projectId,
+ startDate,
+ endDate,
+ events: [
+ {
+ segment: 'event',
+ filters: [
+ ...filters,
+ {
+ id: 'conversion',
+ name: 'name',
+ operator: 'is',
+ value: conversions,
+ },
+ ],
+ id: 'A',
+ name: '*',
+ },
+ ],
+ breakdowns: [
+ {
+ id: 'A',
+ name: 'name',
+ },
+ ],
+ chartType: 'bar',
+ lineType: 'monotone',
+ interval: interval,
+ name: 'Top sources',
+ range: range,
+ previous: previous,
+ metric: 'sum',
+ },
+ },
});
return (
diff --git a/apps/web/src/components/overview/overview-top-geo.tsx b/apps/web/src/components/overview/overview-top-geo.tsx
index 1fa97b93..7e0e3b09 100644
--- a/apps/web/src/components/overview/overview-top-geo.tsx
+++ b/apps/web/src/components/overview/overview-top-geo.tsx
@@ -17,36 +17,6 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
useOverviewOptions();
const [filters, setFilter] = useEventQueryFilters();
const [widget, setWidget, widgets] = useOverviewWidget('geo', {
- map: {
- title: 'Map',
- btn: 'Map',
- chart: {
- projectId,
- startDate,
- endDate,
- events: [
- {
- segment: 'event',
- filters,
- id: 'A',
- name: 'session_start',
- },
- ],
- breakdowns: [
- {
- id: 'A',
- name: 'country',
- },
- ],
- chartType: 'map',
- lineType: 'monotone',
- interval: interval,
- name: 'Top sources',
- range: range,
- previous: previous,
- metric: 'sum',
- },
- },
countries: {
title: 'Top countries',
btn: 'Countries',
@@ -179,6 +149,42 @@ export default function OverviewTopGeo({ projectId }: OverviewTopGeoProps) {
/>
+
+
+ Map
+
+
+
+
+
>
);
}
diff --git a/apps/web/src/components/report/chart/MetricCard.tsx b/apps/web/src/components/report/chart/MetricCard.tsx
index 122b9c54..cbb12418 100644
--- a/apps/web/src/components/report/chart/MetricCard.tsx
+++ b/apps/web/src/components/report/chart/MetricCard.tsx
@@ -11,7 +11,6 @@ import type { IChartMetric } from '@mixan/validation';
import {
getDiffIndicator,
- PreviousDiffIndicator,
PreviousDiffIndicatorText,
} from '../PreviousDiffIndicator';
import { useChartContext } from './ChartProvider';
diff --git a/apps/web/src/components/report/chart/ReportBarChart.tsx b/apps/web/src/components/report/chart/ReportBarChart.tsx
index 24e1040b..1a16025c 100644
--- a/apps/web/src/components/report/chart/ReportBarChart.tsx
+++ b/apps/web/src/components/report/chart/ReportBarChart.tsx
@@ -9,7 +9,7 @@ import { getChartColor } from '@/utils/theme';
import { NOT_SET_VALUE } from '@mixan/constants';
-import { PreviousDiffIndicator } from '../PreviousDiffIndicator';
+import { PreviousDiffIndicatorText } from '../PreviousDiffIndicator';
import { useChartContext } from './ChartProvider';
import { SerieIcon } from './SerieIcon';
@@ -30,42 +30,41 @@ export function ReportBarChart({ data }: ReportBarChartProps) {
- {editMode && (
-
- )}
- {series.map((serie, index) => {
+ {series.map((serie) => {
const isClickable = serie.name !== NOT_SET_VALUE && onClick;
return (
onClick(serie) } : {})}
>
-
+
{serie.name}
-
+
+ {serie.metrics.previous[metric]?.value}
{number.format(serie.metrics.sum)}
-
+
+
);
})}
diff --git a/apps/web/src/components/report/chart/ReportChartTooltip.tsx b/apps/web/src/components/report/chart/ReportChartTooltip.tsx
index 28c889f5..a05dac98 100644
--- a/apps/web/src/components/report/chart/ReportChartTooltip.tsx
+++ b/apps/web/src/components/report/chart/ReportChartTooltip.tsx
@@ -67,15 +67,12 @@ export function ReportChartTooltip({
{getLabel(data.label)}
-
- {number.format(data.count)}
- {unit}
-
+
{number.formatWithUnit(data.count, unit)}
{!!data.previous &&
- `(${data.previous.value + (unit ? unit : '')})`}
+ `(${number.formatWithUnit(data.previous.value, unit)})`}
diff --git a/apps/web/src/components/report/chart/SerieIcon.tsx b/apps/web/src/components/report/chart/SerieIcon.tsx
index dacd14a0..f751b915 100644
--- a/apps/web/src/components/report/chart/SerieIcon.tsx
+++ b/apps/web/src/components/report/chart/SerieIcon.tsx
@@ -30,6 +30,12 @@ const createImageIcon = (url: string) => {
} as LucideIcon;
};
+const createFlagIcon = (url: string) => {
+ return function (props: LucideProps) {
+ return
;
+ } as LucideIcon;
+};
+
const mapper: Record
= {
// Events
screen_view: MonitorPlayIcon,
@@ -88,6 +94,121 @@ const mapper: Record = {
email: MailIcon,
unknown: HelpCircleIcon,
[NOT_SET_VALUE]: ScanIcon,
+
+ // Flags
+ se: createFlagIcon('se'),
+ us: createFlagIcon('us'),
+ gb: createFlagIcon('gb'),
+ ua: createFlagIcon('ua'),
+ ru: createFlagIcon('ru'),
+ de: createFlagIcon('de'),
+ fr: createFlagIcon('fr'),
+ br: createFlagIcon('br'),
+ in: createFlagIcon('in'),
+ it: createFlagIcon('it'),
+ es: createFlagIcon('es'),
+ pl: createFlagIcon('pl'),
+ nl: createFlagIcon('nl'),
+ id: createFlagIcon('id'),
+ tr: createFlagIcon('tr'),
+ ph: createFlagIcon('ph'),
+ ca: createFlagIcon('ca'),
+ ar: createFlagIcon('ar'),
+ mx: createFlagIcon('mx'),
+ za: createFlagIcon('za'),
+ au: createFlagIcon('au'),
+ co: createFlagIcon('co'),
+ ch: createFlagIcon('ch'),
+ at: createFlagIcon('at'),
+ be: createFlagIcon('be'),
+ pt: createFlagIcon('pt'),
+ my: createFlagIcon('my'),
+ th: createFlagIcon('th'),
+ vn: createFlagIcon('vn'),
+ sg: createFlagIcon('sg'),
+ eg: createFlagIcon('eg'),
+ sa: createFlagIcon('sa'),
+ pk: createFlagIcon('pk'),
+ bd: createFlagIcon('bd'),
+ ro: createFlagIcon('ro'),
+ hu: createFlagIcon('hu'),
+ cz: createFlagIcon('cz'),
+ gr: createFlagIcon('gr'),
+ il: createFlagIcon('il'),
+ no: createFlagIcon('no'),
+ fi: createFlagIcon('fi'),
+ dk: createFlagIcon('dk'),
+ sk: createFlagIcon('sk'),
+ bg: createFlagIcon('bg'),
+ hr: createFlagIcon('hr'),
+ rs: createFlagIcon('rs'),
+ ba: createFlagIcon('ba'),
+ si: createFlagIcon('si'),
+ lv: createFlagIcon('lv'),
+ lt: createFlagIcon('lt'),
+ ee: createFlagIcon('ee'),
+ by: createFlagIcon('by'),
+ md: createFlagIcon('md'),
+ kz: createFlagIcon('kz'),
+ uz: createFlagIcon('uz'),
+ kg: createFlagIcon('kg'),
+ tj: createFlagIcon('tj'),
+ tm: createFlagIcon('tm'),
+ az: createFlagIcon('az'),
+ ge: createFlagIcon('ge'),
+ am: createFlagIcon('am'),
+ af: createFlagIcon('af'),
+ ir: createFlagIcon('ir'),
+ iq: createFlagIcon('iq'),
+ sy: createFlagIcon('sy'),
+ lb: createFlagIcon('lb'),
+ jo: createFlagIcon('jo'),
+ ps: createFlagIcon('ps'),
+ kw: createFlagIcon('kw'),
+ qa: createFlagIcon('qa'),
+ om: createFlagIcon('om'),
+ ye: createFlagIcon('ye'),
+ ae: createFlagIcon('ae'),
+ bh: createFlagIcon('bh'),
+ cy: createFlagIcon('cy'),
+ mt: createFlagIcon('mt'),
+ sm: createFlagIcon('sm'),
+ li: createFlagIcon('li'),
+ is: createFlagIcon('is'),
+ al: createFlagIcon('al'),
+ mk: createFlagIcon('mk'),
+ me: createFlagIcon('me'),
+ ad: createFlagIcon('ad'),
+ lu: createFlagIcon('lu'),
+ mc: createFlagIcon('mc'),
+ fo: createFlagIcon('fo'),
+ gg: createFlagIcon('gg'),
+ je: createFlagIcon('je'),
+ im: createFlagIcon('im'),
+ gi: createFlagIcon('gi'),
+ va: createFlagIcon('va'),
+ ax: createFlagIcon('ax'),
+ bl: createFlagIcon('bl'),
+ mf: createFlagIcon('mf'),
+ pm: createFlagIcon('pm'),
+ yt: createFlagIcon('yt'),
+ wf: createFlagIcon('wf'),
+ tf: createFlagIcon('tf'),
+ re: createFlagIcon('re'),
+ sc: createFlagIcon('sc'),
+ mu: createFlagIcon('mu'),
+ zw: createFlagIcon('zw'),
+ mz: createFlagIcon('mz'),
+ na: createFlagIcon('na'),
+ bw: createFlagIcon('bw'),
+ ls: createFlagIcon('ls'),
+ sz: createFlagIcon('sz'),
+ bi: createFlagIcon('bi'),
+ rw: createFlagIcon('rw'),
+ ug: createFlagIcon('ug'),
+ ke: createFlagIcon('ke'),
+ tz: createFlagIcon('tz'),
+ mg: createFlagIcon('mg'),
};
export function SerieIcon({ name, ...props }: SerieIconProps) {
diff --git a/apps/web/src/hooks/useNumerFormatter.ts b/apps/web/src/hooks/useNumerFormatter.ts
index 2533d427..bd9c392b 100644
--- a/apps/web/src/hooks/useNumerFormatter.ts
+++ b/apps/web/src/hooks/useNumerFormatter.ts
@@ -30,5 +30,26 @@ export function useNumber() {
return {
format,
short,
+ shortWithUnit: (value: number | null | undefined, unit?: string | null) => {
+ if (isNil(value)) {
+ return 'N/A';
+ }
+ if (unit === 'min') {
+ return fancyMinutes(value);
+ }
+ return `${short(value)}${unit ? ` ${unit}` : ''}`;
+ },
+ formatWithUnit: (
+ value: number | null | undefined,
+ unit?: string | null
+ ) => {
+ if (isNil(value)) {
+ return 'N/A';
+ }
+ if (unit === 'min') {
+ return fancyMinutes(value);
+ }
+ return `${format(value)}${unit ? ` ${unit}` : ''}`;
+ },
};
}
diff --git a/apps/web/src/modals/AddClient.tsx b/apps/web/src/modals/AddClient.tsx
index 15d03ba9..d700145e 100644
--- a/apps/web/src/modals/AddClient.tsx
+++ b/apps/web/src/modals/AddClient.tsx
@@ -1,17 +1,25 @@
'use client';
+import { useEffect } from 'react';
import { api, handleError } from '@/app/_trpc/client';
-import { ButtonContainer } from '@/components/ButtonContainer';
-import { InputWithLabel } from '@/components/forms/InputWithLabel';
-import Syntax from '@/components/Syntax';
import { Button } from '@/components/ui/button';
-import { Checkbox } from '@/components/ui/checkbox';
+import { CheckboxInput } from '@/components/ui/checkbox';
import { Combobox } from '@/components/ui/combobox';
+import {
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/dialog';
+import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
+import { useAppParams } from '@/hooks/useAppParams';
import { clipboard } from '@/utils/clipboard';
import { zodResolver } from '@hookform/resolvers/zod';
-import { Copy } from 'lucide-react';
+import { Copy, SaveIcon } from 'lucide-react';
+import Link from 'next/link';
import { useRouter } from 'next/navigation';
+import type { SubmitHandler } from 'react-hook-form';
import { Controller, useForm, useWatch } from 'react-hook-form';
import { toast } from 'sonner';
import { z } from 'zod';
@@ -19,194 +27,234 @@ import { z } from 'zod';
import { popModal } from '.';
import { ModalContent, ModalHeader } from './Modal/Container';
-const validator = z.object({
- name: z.string().min(1, 'Required'),
- cors: z.string().min(1, 'Required'),
- withCors: z.boolean(),
- projectId: z.string().min(1, 'Required'),
+const validation = z.object({
+ name: z.string().min(1),
+ domain: z.string().optional(),
+ withSecret: z.boolean().optional(),
+ projectId: z.string(),
});
-type IForm = z.infer;
-interface AddClientProps {
- organizationId: string;
-}
+type IForm = z.infer;
-export default function AddClient({ organizationId }: AddClientProps) {
+export default function AddClient() {
+ const { organizationId, projectId } = useAppParams();
const router = useRouter();
- const query = api.project.list.useQuery({
- organizationId,
+ const form = useForm({
+ resolver: zodResolver(validation),
+ defaultValues: {
+ withSecret: false,
+ name: '',
+ domain: '',
+ projectId,
+ },
});
-
- const mutation = api.client.create.useMutation({
+ const mutation = api.client.create2.useMutation({
onError: handleError,
onSuccess() {
- toast('Success', {
- description: 'Client created!',
- });
+ toast.success('Client created');
router.refresh();
},
});
-
- const { register, handleSubmit, formState, control } = useForm({
- resolver: zodResolver(validator),
- defaultValues: {
- name: '',
- cors: '*',
- projectId: '',
- withCors: true,
- },
+ const query = api.project.list.useQuery({
+ organizationId,
});
+ const onSubmit: SubmitHandler = (values) => {
+ mutation.mutate({
+ name: values.name,
+ domain: values.withSecret ? undefined : values.domain,
+ projectId: values.projectId,
+ organizationId,
+ });
+ };
- const withCors = useWatch({
- control,
- name: 'withCors',
+ const watch = useWatch({
+ control: form.control,
+ name: 'withSecret',
});
- if (mutation.isSuccess && mutation.data) {
- const { clientId, clientSecret, cors } = mutation.data;
- const snippet = clientSecret
- ? `const mixan = new Mixan({
- clientId: "${clientId}",
- // Avoid using this on web, rely on cors settings instead
- // Mostly for react-native and node/backend
- clientSecret: "${clientSecret}",
-})`
- : `const mixan = new Mixan({
- clientId: "${clientId}",
-})`;
- return (
-
-
-
- Your client has been created! You will only see the client secret once
- so keep it safe 🫣
-
-
-
-
- {clientSecret && (
-
- )}
-
-
-
-
-
-
-
- );
- }
-
return (
-
-