refactor packages
This commit is contained in:
@@ -5,7 +5,6 @@ import { StickyBelowHeader } from '@/app/(app)/[organizationId]/[projectId]/layo
|
||||
import { LazyChart } from '@/components/report/chart/LazyChart';
|
||||
import { ReportRange } from '@/components/report/ReportRange';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -14,14 +13,15 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import type { getReportsByDashboardId } from '@/server/services/reports.service';
|
||||
import type { IChartRange } from '@/types';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { getDefaultIntervalByRange, timeRanges } from '@/utils/constants';
|
||||
import { ChevronRight, MoreHorizontal, PlusIcon, Trash } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { getDefaultIntervalByRange } from '@mixan/constants';
|
||||
import type { getReportsByDashboardId } from '@mixan/db';
|
||||
import type { IChartRange } from '@mixan/validation';
|
||||
|
||||
interface ListReportsProps {
|
||||
reports: Awaited<ReturnType<typeof getReportsByDashboardId>>;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { getDashboardById } from '@/server/services/dashboard.service';
|
||||
import { getReportsByDashboardId } from '@/server/services/reports.service';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { getDashboardById, getReportsByDashboardId } from '@mixan/db';
|
||||
|
||||
import { ListReports } from './list-reports';
|
||||
|
||||
interface PageProps {
|
||||
|
||||
@@ -7,12 +7,13 @@ import { Button } from '@/components/ui/button';
|
||||
import { ToastAction } from '@/components/ui/toast';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { pushModal } from '@/modals';
|
||||
import type { IServiceDashboards } from '@/server/services/dashboard.service';
|
||||
import { LayoutPanelTopIcon, Pencil, PlusIcon, Trash } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import type { IServiceDashboards } from '@mixan/db';
|
||||
|
||||
interface ListDashboardsProps {
|
||||
dashboards: IServiceDashboards;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { getDashboardsByProjectId } from '@/server/services/dashboard.service';
|
||||
|
||||
import { getDashboardsByProjectId } from '@mixan/db';
|
||||
|
||||
import { HeaderDashboards } from './header-dashboards';
|
||||
import { ListDashboards } from './list-dashboards';
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
'use client';
|
||||
|
||||
import type { RouterOutputs } from '@/app/_trpc/client';
|
||||
import { ExpandableListItem } from '@/components/general/ExpandableListItem';
|
||||
import { KeyValue, KeyValueSubtle } from '@/components/ui/key-value';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
||||
import {
|
||||
useEventQueryFilters,
|
||||
useEventQueryNamesFilter,
|
||||
} from '@/hooks/useEventQueryFilters';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { getProfileName } from '@/utils/getters';
|
||||
import { round } from '@/utils/math';
|
||||
import { uniq } from 'ramda';
|
||||
|
||||
import type { IServiceCreateEventPayload } from '@mixan/db';
|
||||
|
||||
@@ -40,7 +43,8 @@ export function EventListItem({
|
||||
meta,
|
||||
}: EventListItemProps) {
|
||||
const params = useAppParams();
|
||||
const eventQueryFilters = useEventQueryFilters({ shallow: false });
|
||||
const [, setEvents] = useEventQueryNamesFilter({ shallow: false });
|
||||
const [, setFilter] = useEventQueryFilters({ shallow: false });
|
||||
const keyValueList = [
|
||||
{
|
||||
name: 'Duration',
|
||||
@@ -50,98 +54,98 @@ export function EventListItem({
|
||||
name: 'Referrer',
|
||||
value: referrer,
|
||||
onClick() {
|
||||
eventQueryFilters.referrer.set(referrer ?? null);
|
||||
setFilter('referrer', referrer ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Referrer name',
|
||||
value: referrerName,
|
||||
onClick() {
|
||||
eventQueryFilters.referrerName.set(referrerName ?? null);
|
||||
setFilter('referrer_name', referrerName ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Referrer type',
|
||||
value: referrerType,
|
||||
onClick() {
|
||||
eventQueryFilters.referrerType.set(referrerType ?? null);
|
||||
setFilter('referrer_type', referrerType ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Brand',
|
||||
value: brand,
|
||||
onClick() {
|
||||
eventQueryFilters.brand.set(brand ?? null);
|
||||
setFilter('brand', brand ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Model',
|
||||
value: model,
|
||||
onClick() {
|
||||
eventQueryFilters.model.set(model ?? null);
|
||||
setFilter('model', model ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Browser',
|
||||
value: browser,
|
||||
onClick() {
|
||||
eventQueryFilters.browser.set(browser ?? null);
|
||||
setFilter('browser', browser ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Browser version',
|
||||
value: browserVersion,
|
||||
onClick() {
|
||||
eventQueryFilters.browserVersion.set(browserVersion ?? null);
|
||||
setFilter('browser_version', browserVersion ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'OS',
|
||||
value: os,
|
||||
onClick() {
|
||||
eventQueryFilters.os.set(os ?? null);
|
||||
setFilter('os', os ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'OS cersion',
|
||||
value: osVersion,
|
||||
onClick() {
|
||||
eventQueryFilters.osVersion.set(osVersion ?? null);
|
||||
setFilter('os_version', osVersion ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'City',
|
||||
value: city,
|
||||
onClick() {
|
||||
eventQueryFilters.city.set(city ?? null);
|
||||
setFilter('city', city ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Region',
|
||||
value: region,
|
||||
onClick() {
|
||||
eventQueryFilters.region.set(region ?? null);
|
||||
setFilter('region', region ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Country',
|
||||
value: country,
|
||||
onClick() {
|
||||
eventQueryFilters.country.set(country ?? null);
|
||||
setFilter('country', country ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Continent',
|
||||
value: continent,
|
||||
onClick() {
|
||||
eventQueryFilters.continent.set(continent ?? null);
|
||||
setFilter('continent', continent ?? '');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Device',
|
||||
value: device,
|
||||
onClick() {
|
||||
eventQueryFilters.device.set(device ?? null);
|
||||
setFilter('device', device ?? '');
|
||||
},
|
||||
},
|
||||
].filter((item) => typeof item.value === 'string' && item.value);
|
||||
@@ -156,7 +160,11 @@ export function EventListItem({
|
||||
return (
|
||||
<ExpandableListItem
|
||||
className={cn(meta?.conversion && 'ring-2 ring-primary-500')}
|
||||
title={name.split('_').join(' ')}
|
||||
title={
|
||||
<button onClick={() => setEvents((p) => uniq([...p, name]))}>
|
||||
{name.split('_').join(' ')}
|
||||
</button>
|
||||
}
|
||||
content={
|
||||
<>
|
||||
<KeyValueSubtle name="Time" value={createdAt.toLocaleString()} />
|
||||
@@ -172,7 +180,7 @@ export function EventListItem({
|
||||
name="Path"
|
||||
value={path}
|
||||
onClick={() => {
|
||||
eventQueryFilters.path.set(path);
|
||||
setFilter('path', path);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -191,6 +199,13 @@ export function EventListItem({
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
value={item.value}
|
||||
onClick={() => {
|
||||
setFilter(
|
||||
`properties.${item.name}`,
|
||||
item.value ? String(item.value) : '',
|
||||
'is'
|
||||
);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { FullPageEmptyState } from '@/components/FullPageEmptyState';
|
||||
import { Pagination } from '@/components/Pagination';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCursor } from '@/hooks/useCursor';
|
||||
import { useEventFilters } from '@/hooks/useEventQueryFilters';
|
||||
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
||||
import { GanttChartIcon } from 'lucide-react';
|
||||
|
||||
import type { IServiceCreateEventPayload } from '@mixan/db';
|
||||
@@ -18,8 +18,7 @@ interface EventListProps {
|
||||
}
|
||||
export function EventList({ data, count }: EventListProps) {
|
||||
const { cursor, setCursor } = useCursor();
|
||||
const filters = useEventFilters();
|
||||
|
||||
const [filters] = useEventQueryFilters();
|
||||
return (
|
||||
<Suspense>
|
||||
<div className="p-4">
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { OverviewFiltersButtons } from '@/components/overview/filters/overview-filters-buttons';
|
||||
import { OverviewFiltersDrawer } from '@/components/overview/filters/overview-filters-drawer';
|
||||
import { getEventFilters } from '@/hooks/useEventQueryFilters';
|
||||
import {
|
||||
eventQueryFiltersParser,
|
||||
eventQueryNamesFilter,
|
||||
} from '@/hooks/useEventQueryFilters';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
|
||||
import { getEventList, getEventsCount } from '@mixan/db';
|
||||
@@ -15,27 +18,9 @@ interface PageProps {
|
||||
organizationId: string;
|
||||
};
|
||||
searchParams: {
|
||||
events?: string;
|
||||
cursor?: string;
|
||||
path?: string;
|
||||
device?: string;
|
||||
referrer?: string;
|
||||
referrerName?: string;
|
||||
referrerType?: string;
|
||||
utmSource?: string;
|
||||
utmMedium?: string;
|
||||
utmCampaign?: string;
|
||||
utmContent?: string;
|
||||
utmTerm?: string;
|
||||
continent?: string;
|
||||
country?: string;
|
||||
region?: string;
|
||||
city?: string;
|
||||
browser?: string;
|
||||
browserVersion?: string;
|
||||
os?: string;
|
||||
osVersion?: string;
|
||||
brand?: string;
|
||||
model?: string;
|
||||
f?: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,53 +44,13 @@ export default async function Page({
|
||||
cursor: parseQueryAsNumber(searchParams.cursor),
|
||||
projectId,
|
||||
take: 50,
|
||||
filters: getEventFilters({
|
||||
path: searchParams.path ?? null,
|
||||
device: searchParams.device ?? null,
|
||||
referrer: searchParams.referrer ?? null,
|
||||
referrerName: searchParams.referrerName ?? null,
|
||||
referrerType: searchParams.referrerType ?? null,
|
||||
utmSource: searchParams.utmSource ?? null,
|
||||
utmMedium: searchParams.utmMedium ?? null,
|
||||
utmCampaign: searchParams.utmCampaign ?? null,
|
||||
utmContent: searchParams.utmContent ?? null,
|
||||
utmTerm: searchParams.utmTerm ?? null,
|
||||
continent: searchParams.continent ?? null,
|
||||
country: searchParams.country ?? null,
|
||||
region: searchParams.region ?? null,
|
||||
city: searchParams.city ?? null,
|
||||
browser: searchParams.browser ?? null,
|
||||
browserVersion: searchParams.browserVersion ?? null,
|
||||
os: searchParams.os ?? null,
|
||||
osVersion: searchParams.osVersion ?? null,
|
||||
brand: searchParams.brand ?? null,
|
||||
model: searchParams.model ?? null,
|
||||
}),
|
||||
events: eventQueryNamesFilter.parse(searchParams.events ?? ''),
|
||||
filters: eventQueryFiltersParser.parse(searchParams.f ?? '') ?? undefined,
|
||||
}),
|
||||
getEventsCount({
|
||||
projectId,
|
||||
filters: getEventFilters({
|
||||
path: searchParams.path ?? null,
|
||||
device: searchParams.device ?? null,
|
||||
referrer: searchParams.referrer ?? null,
|
||||
referrerName: searchParams.referrerName ?? null,
|
||||
referrerType: searchParams.referrerType ?? null,
|
||||
utmSource: searchParams.utmSource ?? null,
|
||||
utmMedium: searchParams.utmMedium ?? null,
|
||||
utmCampaign: searchParams.utmCampaign ?? null,
|
||||
utmContent: searchParams.utmContent ?? null,
|
||||
utmTerm: searchParams.utmTerm ?? null,
|
||||
continent: searchParams.continent ?? null,
|
||||
country: searchParams.country ?? null,
|
||||
region: searchParams.region ?? null,
|
||||
city: searchParams.city ?? null,
|
||||
browser: searchParams.browser ?? null,
|
||||
browserVersion: searchParams.browserVersion ?? null,
|
||||
os: searchParams.os ?? null,
|
||||
osVersion: searchParams.osVersion ?? null,
|
||||
brand: searchParams.brand ?? null,
|
||||
model: searchParams.model ?? null,
|
||||
}),
|
||||
events: eventQueryNamesFilter.parse(searchParams.events ?? ''),
|
||||
filters: eventQueryFiltersParser.parse(searchParams.f ?? '') ?? undefined,
|
||||
}),
|
||||
getExists(organizationId, projectId),
|
||||
]);
|
||||
@@ -116,6 +61,7 @@ export default async function Page({
|
||||
<OverviewFiltersDrawer
|
||||
projectId={projectId}
|
||||
nuqsOptions={nuqsOptions}
|
||||
enableEventsFilter
|
||||
/>
|
||||
<OverviewFiltersButtons
|
||||
className="p-0 justify-end"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import type { IServiceDashboards } from '@/server/services/dashboard.service';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { useUser } from '@clerk/nextjs';
|
||||
import {
|
||||
@@ -21,6 +20,8 @@ import type { LucideProps } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
import type { IServiceDashboards } from '@mixan/db';
|
||||
|
||||
function LinkWithIcon({
|
||||
href,
|
||||
icon: Icon,
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import type { IServiceOrganization } from '@/server/services/organization.service';
|
||||
import { Building } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import type { IServiceOrganization } from '@mixan/db';
|
||||
|
||||
interface LayoutOrganizationSelectorProps {
|
||||
organizations: IServiceOrganization[];
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
import { Combobox } from '@/components/ui/combobox';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import type { getCurrentProjects } from '@/server/services/project.service';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
|
||||
import type { getProjectsByOrganizationSlug } from '@mixan/db';
|
||||
|
||||
interface LayoutProjectSelectorProps {
|
||||
projects: Awaited<ReturnType<typeof getCurrentProjects>>;
|
||||
projects: Awaited<ReturnType<typeof getProjectsByOrganizationSlug>>;
|
||||
}
|
||||
export default function LayoutProjectSelector({
|
||||
projects,
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Logo } from '@/components/Logo';
|
||||
import type { IServiceDashboards } from '@/server/services/dashboard.service';
|
||||
import type { IServiceOrganization } from '@/server/services/organization.service';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { Rotate as Hamburger } from 'hamburger-react';
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
import type { IServiceDashboards, IServiceOrganization } from '@mixan/db';
|
||||
|
||||
import LayoutMenu from './layout-menu';
|
||||
import LayoutOrganizationSelector from './layout-organization-selector';
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { getDashboardsByOrganization } from '@/server/services/dashboard.service';
|
||||
import { getCurrentOrganizations } from '@/server/services/organization.service';
|
||||
import {
|
||||
getCurrentOrganizations,
|
||||
getDashboardsByOrganization,
|
||||
} from '@mixan/db';
|
||||
|
||||
import { LayoutSidebar } from './layout-sidebar';
|
||||
|
||||
|
||||
@@ -4,17 +4,18 @@ import { WidgetHead } from '@/components/overview/overview-widget';
|
||||
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||
import { Chart } from '@/components/report/chart';
|
||||
import { Widget, WidgetBody } from '@/components/Widget';
|
||||
import { useEventFilters } from '@/hooks/useEventQueryFilters';
|
||||
import type { IChartInput } from '@/types';
|
||||
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
||||
import { cn } from '@/utils/cn';
|
||||
|
||||
import type { IChartInput } from '@mixan/validation';
|
||||
|
||||
interface OverviewMetricsProps {
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
||||
const { previous, range, interval, metric, setMetric } = useOverviewOptions();
|
||||
const filters = useEventFilters();
|
||||
const [filters] = useEventQueryFilters();
|
||||
|
||||
const reports = [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getCurrentProjects } from '@/server/services/project.service';
|
||||
import { getProjectsByOrganizationSlug } from '@mixan/db';
|
||||
|
||||
import LayoutProjectSelector from './layout-project-selector';
|
||||
|
||||
@@ -13,7 +13,7 @@ export default async function PageLayout({
|
||||
title,
|
||||
organizationSlug,
|
||||
}: PageLayoutProps) {
|
||||
const projects = await getCurrentProjects(organizationSlug);
|
||||
const projects = await getProjectsByOrganizationSlug(organizationSlug);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function ListProfileEvents({
|
||||
projectId,
|
||||
profileId,
|
||||
}: ListProfileEvents) {
|
||||
const pagination = usePagination();
|
||||
const pagination = usePagination(50);
|
||||
const [eventFilters, setEventFilters] = useQueryState(
|
||||
'events',
|
||||
parseAsJson<string[]>().withDefault([])
|
||||
|
||||
@@ -3,13 +3,11 @@ import { ListProperties } from '@/components/events/ListProperties';
|
||||
import { ProfileAvatar } from '@/components/profiles/ProfileAvatar';
|
||||
import { Widget, WidgetBody, WidgetHead } from '@/components/Widget';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import {
|
||||
getProfileById,
|
||||
getProfilesByExternalId,
|
||||
} from '@/server/services/profile.service';
|
||||
import { formatDateTime } from '@/utils/date';
|
||||
import { getProfileName } from '@/utils/getters';
|
||||
|
||||
import { getProfileById, getProfilesByExternalId } from '@mixan/db';
|
||||
|
||||
import ListProfileEvents from './list-profile-events';
|
||||
|
||||
interface PageProps {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import type { RouterOutputs } from '@/app/_trpc/client';
|
||||
import { ListProperties } from '@/components/events/ListProperties';
|
||||
import { ExpandableListItem } from '@/components/general/ExpandableListItem';
|
||||
@@ -16,24 +15,24 @@ export function ProfileListItem(props: ProfileListItemProps) {
|
||||
const { id, properties, createdAt } = props;
|
||||
const params = useAppParams();
|
||||
|
||||
const bullets = useMemo(() => {
|
||||
const bullets: React.ReactNode[] = [
|
||||
<span>{formatDateTime(createdAt)}</span>,
|
||||
<Link
|
||||
href={`/${params.organizationId}/${params.projectId}/profiles/${id}`}
|
||||
className="text-black font-medium hover:underline"
|
||||
>
|
||||
See profile
|
||||
</Link>,
|
||||
];
|
||||
|
||||
return bullets;
|
||||
}, [createdAt, id, params]);
|
||||
const renderContent = () => {
|
||||
return (
|
||||
<>
|
||||
<span>{formatDateTime(createdAt)}</span>
|
||||
<Link
|
||||
href={`/${params.organizationId}/${params.projectId}/profiles/${id}`}
|
||||
className="text-black font-medium hover:underline"
|
||||
>
|
||||
See profile
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ExpandableListItem
|
||||
title={getProfileName(props)}
|
||||
bullets={bullets}
|
||||
content={renderContent()}
|
||||
image={<ProfileAvatar {...props} />}
|
||||
>
|
||||
<ListProperties data={properties} className="rounded-none border-none" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { getOrganizationBySlug } from '@/server/services/organization.service';
|
||||
import { getReportById } from '@/server/services/reports.service';
|
||||
import { Pencil } from 'lucide-react';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { getOrganizationBySlug, getReportById } from '@mixan/db';
|
||||
|
||||
import ReportEditor from '../report-editor';
|
||||
|
||||
interface PageProps {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { getOrganizationBySlug } from '@/server/services/organization.service';
|
||||
import { Pencil } from 'lucide-react';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { getOrganizationBySlug } from '@mixan/db';
|
||||
|
||||
import ReportEditor from './report-editor';
|
||||
|
||||
interface PageProps {
|
||||
|
||||
@@ -19,9 +19,10 @@ import { Button } from '@/components/ui/button';
|
||||
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { useDispatch, useSelector } from '@/redux';
|
||||
import type { IServiceReport } from '@/server/services/reports.service';
|
||||
import { GanttChartSquareIcon } from 'lucide-react';
|
||||
|
||||
import type { IServiceReport } from '@mixan/db';
|
||||
|
||||
interface ReportEditorProps {
|
||||
report: IServiceReport | null;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ import { DataTable } from '@/components/DataTable';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { pushModal } from '@/modals';
|
||||
import type { getClientsByOrganizationId } from '@/server/services/clients.service';
|
||||
import { PlusIcon } from 'lucide-react';
|
||||
|
||||
import type { getClientsByOrganizationId } from '@mixan/db';
|
||||
|
||||
interface ListClientsProps {
|
||||
clients: Awaited<ReturnType<typeof getClientsByOrganizationId>>;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { getClientsByOrganizationId } from '@/server/services/clients.service';
|
||||
|
||||
import { getClientsByOrganizationId } from '@mixan/db';
|
||||
|
||||
import ListClients from './list-clients';
|
||||
|
||||
|
||||
@@ -4,12 +4,13 @@ import { api, handleError } from '@/app/_trpc/client';
|
||||
import { InputWithLabel } from '@/components/forms/InputWithLabel';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Widget, WidgetBody, WidgetHead } from '@/components/Widget';
|
||||
import type { getOrganizationBySlug } from '@/server/services/organization.service';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { getOrganizationBySlug } from '@mixan/db';
|
||||
|
||||
const validator = z.object({
|
||||
id: z.string().min(2),
|
||||
name: z.string().min(2),
|
||||
|
||||
@@ -2,7 +2,6 @@ import { api } from '@/app/_trpc/client';
|
||||
import { InputWithLabel } from '@/components/forms/InputWithLabel';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { zInviteUser } from '@/utils/validation';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { SendIcon } from 'lucide-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
@@ -10,6 +9,8 @@ import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { zInviteUser } from '@mixan/validation';
|
||||
|
||||
type IForm = z.infer<typeof zInviteUser>;
|
||||
|
||||
export function InviteUser() {
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { Widget, WidgetBody, WidgetHead } from '@/components/Widget';
|
||||
import type { IServiceInvites } from '@/server/services/organization.service';
|
||||
|
||||
import type { IServiceInvites } from '@mixan/db';
|
||||
|
||||
import { InviteUser } from './invite-user';
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import {
|
||||
getInvites,
|
||||
getOrganizationBySlug,
|
||||
} from '@/server/services/organization.service';
|
||||
import { clerkClient } from '@clerk/nextjs';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { getInvites, getOrganizationBySlug } from '@mixan/db';
|
||||
|
||||
import EditOrganization from './edit-organization';
|
||||
import InvitedUsers from './invited-users';
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ import { api, handleError } from '@/app/_trpc/client';
|
||||
import { InputWithLabel } from '@/components/forms/InputWithLabel';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Widget, WidgetBody, WidgetHead } from '@/components/Widget';
|
||||
import type { getUserById } from '@/server/services/user.service';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { toast } from 'sonner';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { getUserById } from '@mixan/db';
|
||||
|
||||
const validator = z.object({
|
||||
firstName: z.string().min(2),
|
||||
lastName: z.string().min(2),
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { getUserById } from '@/server/services/user.service';
|
||||
import { auth } from '@clerk/nextjs';
|
||||
|
||||
import { getUserById } from '@mixan/db';
|
||||
|
||||
import EditProfile from './edit-profile';
|
||||
import { Logout } from './logout';
|
||||
|
||||
|
||||
@@ -6,11 +6,12 @@ import { columns } from '@/components/projects/table';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAppParams } from '@/hooks/useAppParams';
|
||||
import { pushModal } from '@/modals';
|
||||
import type { getProjectsByOrganizationId } from '@/server/services/project.service';
|
||||
import { PlusIcon } from 'lucide-react';
|
||||
|
||||
import type { getProjectsByOrganizationSlug } from '@mixan/db';
|
||||
|
||||
interface ListProjectsProps {
|
||||
projects: Awaited<ReturnType<typeof getProjectsByOrganizationId>>;
|
||||
projects: Awaited<ReturnType<typeof getProjectsByOrganizationSlug>>;
|
||||
}
|
||||
export default function ListProjects({ projects }: ListProjectsProps) {
|
||||
const organizationId = useAppParams().organizationId;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import PageLayout from '@/app/(app)/[organizationId]/[projectId]/page-layout';
|
||||
import { getExists } from '@/server/pageExists';
|
||||
import { getProjectsByOrganizationSlug } from '@/server/services/project.service';
|
||||
|
||||
import { getProjectsByOrganizationSlug } from '@mixan/db';
|
||||
|
||||
import ListProjects from './list-projects';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user