Skip to content

Commit

Permalink
insights follow up (calcom#7922)
Browse files Browse the repository at this point in the history
* init page

* init insights frontend

* nit

* nit

* nit

* merge

* fixed icons

* i18n, needs features

* Init insights trpc

* Using trpc on client

* Added events timeline

* Seed analytics script

* connect ui with trpc

* Added and fixed event time lines

* WIP popular days and avg time duration event type

* added new metric graphs

* improved upgrade tip

* always show upgrade screen

* upgrade tremor.so and select inputs for page

* Remove log

* Move everything to components and add context

* Fix select types using calcom ui one

* Adding translations

* Add missing translations

* Add more translations

* min fix

* Fixes for date select

* Prefer early return and mobile design fixes

* Fix style for mobile

* Fix data with userId filter from popular events

* add user id to average time duration

* fix types for select-react

* Removed submodules

* Delete website

* Update yarn.lock

* Code organization and type fixes

* trpc fixes

* Builds are now passing

* Relocates server code

* Add url state in insights

* Update FiltersProvider.tsx

* Cleanup

* Update embed-iframe.ts

* Update FilterType.tsx

* Update seed-app-store.config.json

* Update index.tsx

* Renamed seeder

* Update FiltersProvider.tsx

* Fix for query params

* no wrap on lg screen

* Fix shadow borders from tremor components, fix title font

* Add ring-gray to match filters

* add cursor pointer

* copy improvements

* blue to black

* fixed date select focus

* Adds missing translation strings

* Fix url state for filter type

* Apply suggestions from code review

* Updated yarn lock

* Adds feature flag

* Type fix

---------

Co-authored-by: Peer Richelsen <[email protected]>
Co-authored-by: Peer Richelsen <[email protected]>
Co-authored-by: zomars <[email protected]>
  • Loading branch information
4 people authored Mar 28, 2023
1 parent 3a08eb3 commit 6c51e2a
Show file tree
Hide file tree
Showing 24 changed files with 339 additions and 130 deletions.
39 changes: 38 additions & 1 deletion apps/web/pages/404.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useEffect, useState } from "react";
import { COMPANY_NAME, DEVELOPER_DOCS, DOCS_URL, JOIN_SLACK, WEBSITE_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HeadSeo } from "@calcom/ui";
import { FiFileText, FiCheck, FiBookOpen, FiChevronRight } from "@calcom/ui/components/icon";
import { FiBookOpen, FiCheck, FiChevronRight, FiFileText } from "@calcom/ui/components/icon";

import { ssgInit } from "@server/lib/ssg";

Expand Down Expand Up @@ -40,6 +40,43 @@ export default function Custom404() {
const isSubpage = router.asPath.includes("/", 2) || isSuccessPage;
const isSignup = router.asPath.startsWith("/signup");
const isCalcom = process.env.NEXT_PUBLIC_WEBAPP_URL === "https://app.cal.com";
/**
* If we're on 404 and the route is insights it means it is disabled
* TODO: Abstract this for all disabled features
**/
const isInsights = router.asPath.startsWith("/insights");
if (isInsights) {
return (
<>
<HeadSeo
title="Feature is currently disabled"
description={t("404_page_not_found")}
nextSeoProps={{
nofollow: true,
noindex: true,
}}
/>
<div className="min-h-screen bg-white px-4" data-testid="404-page">
<main className="mx-auto max-w-xl pt-16 pb-6 sm:pt-24">
<div className="text-center">
<p className="text-sm font-semibold uppercase tracking-wide text-black">{t("error_404")}</p>
<h1 className="font-cal mt-2 text-4xl font-extrabold text-gray-900 sm:text-5xl">
Feature is currently disabled
</h1>
</div>
<div className="mt-12">
<div className="mt-8">
<Link href="/" className="text-base font-medium text-black hover:text-gray-500">
{t("or_go_back_home")}
<span aria-hidden="true"> &rarr;</span>
</Link>
</div>
</div>
</main>
</div>
</>
);
}

return (
<>
Expand Down
23 changes: 20 additions & 3 deletions apps/web/pages/insights/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
import {
AverageEventDurationChart,
BookingKPICards,
Expand Down Expand Up @@ -39,17 +40,17 @@ export default function InsightsPage() {
const { data: user } = trpc.viewer.me.useQuery();
const features = [
{
icon: <FiUsers className="h-5 w-5 text-red-500" />,
icon: <FiUsers className="h-5 w-5" />,
title: t("view_bookings_across"),
description: t("view_bookings_across_description"),
},
{
icon: <FiRefreshCcw className="h-5 w-5 text-blue-500" />,
icon: <FiRefreshCcw className="h-5 w-5" />,
title: t("identify_booking_trends"),
description: t("identify_booking_trends_description"),
},
{
icon: <FiUserPlus className="h-5 w-5 text-green-500" />,
icon: <FiUserPlus className="h-5 w-5" />,
title: t("spot_popular_event_types"),
description: t("spot_popular_event_types_description"),
},
Expand Down Expand Up @@ -114,3 +115,19 @@ export default function InsightsPage() {
</div>
);
}

// If feature flag is disabled, return not found on getServerSideProps
export const getServerSideProps = async () => {
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
const flags = await getFeatureFlagMap(prisma);

if (flags.insights === false) {
return {
notFound: true,
};
}

return {
props: {},
};
};
9 changes: 6 additions & 3 deletions apps/web/public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,7 @@
"impersonation": "Impersonation",
"impersonation_description": "Settings to manage user impersonation",
"users": "Users",
"user": "User",
"profile_description": "Manage settings for your {{appName}} profile",
"users_description": "Here you can find a list of all users",
"users_listing": "User listing",
Expand Down Expand Up @@ -1687,7 +1688,9 @@
"events_rescheduled": "Events Rescheduled",
"from_last_period": "from last period",
"from_to_date_period": "From: {{startDate}} To: {{endDate}}",
"analytics_for_organisation": "Analytics for {{organisationName}}",
"subtitle_analytics": "This is a organisation analytics",
"event_trends": "Event Trends"
"analytics_for_organisation": "Insights for {{organisationName}}",
"subtitle_analytics": "Learn more about your team's activity",
"event_trends": "Event Trends",
"clear_filters": "Clear Filters",
"insights": "Insights"
}
1 change: 1 addition & 0 deletions apps/web/public/static/locales/es/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,7 @@
"impersonation": "Suplantación",
"impersonation_description": "Configuración para administrar la suplantación del usuario",
"users": "Usuarios",
"user": "Usuario",
"profile_description": "Administra los ajustes para tu perfil de {{appName}}",
"users_description": "Aquí puede encontrar una lista de todos los usuarios",
"users_listing": "Lista de usuarios",
Expand Down
2 changes: 2 additions & 0 deletions apps/web/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,5 @@ hr {
::-webkit-search-cancel-button {
-webkit-appearance: none;
}


3 changes: 2 additions & 1 deletion packages/features/flags/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
**/
export type AppFlags = {
emails: boolean;
insights: boolean;
teams: boolean;
webhooks: boolean;
workflows: boolean;
"booking-page-v2": boolean;
"v2-booking-page": boolean;
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Card, LineChart, Title } from "@tremor/react";
import { LineChart, Title } from "@tremor/react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";

import { useFilterContext } from "../context/provider";
import { valueFormatter } from "../lib/valueFormatter";
import { CardInsights } from "./Card";

export const AverageEventDurationChart = () => {
const { t } = useLocale();
Expand All @@ -23,7 +24,7 @@ export const AverageEventDurationChart = () => {
if (!isSuccess || data?.length == 0 || !startDate || !endDate || !teamId) return null;

return (
<Card>
<CardInsights>
<Title>{t("average_event_duration")}</Title>
<LineChart
className="mt-4 h-80"
Expand All @@ -33,6 +34,6 @@ export const AverageEventDurationChart = () => {
colors={["blue"]}
valueFormatter={valueFormatter}
/>
</Card>
</CardInsights>
);
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Card, LineChart, Title } from "@tremor/react";
import { LineChart, Title } from "@tremor/react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";

import { useFilterContext } from "../context/provider";
import { valueFormatter } from "../lib/valueFormatter";
import { CardInsights } from "./Card";

export const BookingStatusLineChart = () => {
const { t } = useLocale();
Expand All @@ -25,7 +26,7 @@ export const BookingStatusLineChart = () => {
if (!isSuccess) return null;

return (
<Card>
<CardInsights>
<Title>{t("event_trends")}</Title>
<LineChart
className="mt-4 h-80"
Expand All @@ -35,6 +36,6 @@ export const BookingStatusLineChart = () => {
colors={["gray", "green", "blue", "red"]}
valueFormatter={valueFormatter}
/>
</Card>
</CardInsights>
);
};
17 changes: 17 additions & 0 deletions packages/features/insights/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Card } from "@tremor/react";

interface ICardProps {
children: React.ReactNode;
className?: string;
}

export const CardInsights = (props: ICardProps) => {
const { children, className = "", ...rest } = props;

return (
<Card className={`shadow-none ring-gray-300 ${className}`} {...rest}>
{children}
</Card>
);
};

11 changes: 7 additions & 4 deletions packages/features/insights/components/KPICard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Card, Flex, Text, Metric, BadgeDelta } from "@tremor/react";
import { Flex, Text, Metric, BadgeDelta } from "@tremor/react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Tooltip } from "@calcom/ui";

import { calculateDeltaType, colors, valueFormatter } from "../lib";
import { CardInsights } from "./Card";

export const KPICard = ({
title,
Expand All @@ -20,7 +21,7 @@ export const KPICard = ({
}) => {
const { t } = useLocale();
return (
<Card key={title}>
<CardInsights key={title}>
<Text>{title}</Text>
<Flex className="items-baseline justify-start space-x-3 truncate">
<Metric>{valueFormatter(previousMetricData.count)}</Metric>
Expand All @@ -40,10 +41,12 @@ export const KPICard = ({
startDate: previousDateRange.startDate,
endDate: previousDateRange.endDate,
})}>
<small className="relative top-px text-xs text-gray-600">{t("from_last_period")}</small>
<small className="relative top-px cursor-pointer text-xs text-gray-600">
{t("from_last_period")}
</small>
</Tooltip>
</Flex>
</Flex>
</Card>
</CardInsights>
);
};
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import { Card, Title } from "@tremor/react";
import { Title } from "@tremor/react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";

import { useFilterContext } from "../context/provider";
import { CardInsights } from "./Card";
import { TotalBookingUsersTable } from "./TotalBookingUsersTable";

export const LeastBookedTeamMembersTable = () => {
const { t } = useLocale();
const { filter } = useFilterContext();
const { dateRange } = filter;
const { dateRange, selectedEventTypeId, selectedTeamId: teamId } = filter;
const [startDate, endDate] = dateRange;
const { selectedTeamId: teamId } = filter;

const { data, isSuccess } = trpc.viewer.insights.membersWithLeastBookings.useQuery({
startDate: startDate.toISOString(),
endDate: endDate.toISOString(),
teamId,
eventTypeId: selectedEventTypeId ?? undefined,
});

if (!isSuccess || !startDate || !endDate || !teamId) return null;

return (
<Card>
<CardInsights>
<Title>{t("least_booked_members")}</Title>
<TotalBookingUsersTable data={data} />
</Card>
</CardInsights>
);
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Card, Title } from "@tremor/react";
import { Title } from "@tremor/react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";

import { useFilterContext } from "../context/provider";
import { CardInsights } from "./Card";
import { TotalBookingUsersTable } from "./TotalBookingUsersTable";

export const MostBookedTeamMembersTable = () => {
Expand All @@ -23,9 +24,9 @@ export const MostBookedTeamMembersTable = () => {
if (!isSuccess || !startDate || !endDate || !teamId) return null;

return (
<Card>
<CardInsights className="shadow-none">
<Title>{t("most_booked_members")}</Title>
<TotalBookingUsersTable data={data} />
</Card>
</CardInsights>
);
};
32 changes: 12 additions & 20 deletions packages/features/insights/components/PopularEventsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Card, Title, Table, TableBody, TableCell, TableRow, Text } from "@tremor/react";
import { Table, TableBody, TableCell, TableRow, Text, Title } from "@tremor/react";

import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";

import { useFilterContext } from "../context/provider";
import { CardInsights } from "./Card";

export const PopularEventsTable = () => {
const { t } = useLocale();
Expand All @@ -19,34 +20,25 @@ export const PopularEventsTable = () => {
userId: selectedUserId ?? undefined,
});

if (!startDate || !endDate || !teamId) return null;
if (!isSuccess || !startDate || !endDate || !teamId || data?.length === 0) return null;

return (
<Card>
<CardInsights>
<Title>{t("popular_events")}</Title>
<Table className="mt-5">
<TableBody>
{isSuccess ? (
data?.map((item) => (
<TableRow key={item.eventTypeId}>
<TableCell>{item.eventTypeName}</TableCell>
<TableCell>
<Text>
<strong>{item.count}</strong>
</Text>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell>{t("no_event_types_found")}</TableCell>
{data.map((item) => (
<TableRow key={item.eventTypeId}>
<TableCell>{item.eventTypeName}</TableCell>
<TableCell>
<strong>0</strong>
<Text>
<strong>{item.count}</strong>
</Text>
</TableCell>
</TableRow>
)}
))}
</TableBody>
</Table>
</Card>
</CardInsights>
);
};
Loading

0 comments on commit 6c51e2a

Please sign in to comment.