Add AppStore General Settings support (#4998)
* added weather in calendar wrapper * added textfield to weather app, needs GeneralSettings abstraction * add automation cateogry for n8n and zapier * fix border radius for seperated apps * create app specific settings in installed apps * Fixed design issues caused by app settings * add first version of template cards with logos * Add link to zapier template * Add missing translations * fix mobile view * better readable app description in mobile view * code clean up * fix issue that lisItem was always expanded * code clean up * code clean up * fix import * fix typo * code clean up * Add AppStore General Settings support * add missing alt to img * use FiShare2 icon instead of FiZap * Remove duplicate entries * Add border to AppSettings consistently Co-authored-by: Peer Richelsen <peer@cal.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Co-authored-by: Alex van Andel <me@alexvanandel.com>
This commit is contained in:
co-authored by
Peer Richelsen
Peer Richelsen
CarinaWolli
Carina Wollendorfer
Alex van Andel
parent
6ee9de6dd8
commit
cf423dda70
@@ -141,6 +141,7 @@ function CalendarList(props: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
// todo: @hariom extract this into packages/apps-store as "GeneralAppSettings"
|
||||
function ConnectedCalendarsList(props: Props) {
|
||||
const { t } = useLocale();
|
||||
const query = trpc.useQuery(["viewer.connectedCalendars"], { suspense: true });
|
||||
|
||||
@@ -96,19 +96,18 @@ interface IntegrationsListProps {
|
||||
data: inferQueryOutput<"viewer.integrations">;
|
||||
}
|
||||
|
||||
const IntegrationsList = ({ data, variant }: IntegrationsListProps) => {
|
||||
const separateItems = variant === "automation";
|
||||
const IntegrationsList = ({ data }: IntegrationsListProps) => {
|
||||
return (
|
||||
<List className={classNames(separateItems ? "flex flex-col gap-6" : "")} noBorderTreatment>
|
||||
<List className="flex flex-col gap-6" noBorderTreatment>
|
||||
{data.items.map((item) => (
|
||||
<IntegrationListItem
|
||||
name={item.name}
|
||||
slug={item.slug}
|
||||
key={item.name}
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
logo={item.logo}
|
||||
description={item.description}
|
||||
separate={separateItems}
|
||||
separate={true}
|
||||
actions={
|
||||
<div className="flex w-16 justify-end">
|
||||
<ConnectOrDisconnectIntegrationButton
|
||||
@@ -119,7 +118,9 @@ const IntegrationsList = ({ data, variant }: IntegrationsListProps) => {
|
||||
/>
|
||||
</div>
|
||||
}>
|
||||
{separateItems && <AppSettings slug={item.slug} />}
|
||||
<div className="border-t border-gray-200">
|
||||
<AppSettings slug={item.slug} />
|
||||
</div>
|
||||
</IntegrationListItem>
|
||||
))}
|
||||
</List>
|
||||
|
||||
@@ -198,6 +198,15 @@ function generateFiles() {
|
||||
})
|
||||
);
|
||||
|
||||
// TODO: Make a component map creator that accepts ComponentName and does the rest.
|
||||
// TODO: dailyvideo has a slug of daily-video, so that mapping needs to be taken care of. But it is an old app, so it doesn't need AppSettings
|
||||
browserOutput.push(
|
||||
...getObjectExporter("AppSettingsComponentsMap", {
|
||||
fileToBeImported: "components/AppSettings.tsx",
|
||||
entryBuilder: (app) => ` ${app.name}: dynamic(() =>import("./${app.path}/components/AppSettings")),`,
|
||||
})
|
||||
);
|
||||
|
||||
browserOutput.push(
|
||||
...getObjectExporter("EventTypeAddonMap", {
|
||||
fileToBeImported: path.join("extensions", "EventTypeAppCard.tsx"),
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import dynamic from "next/dynamic";
|
||||
import { AppSettingsComponentsMap } from "@calcom/app-store/apps.browser.generated";
|
||||
|
||||
import { DynamicComponent } from "./DynamicComponent";
|
||||
|
||||
export const AppSettingsMap = {
|
||||
zapier: dynamic(() => import("../zapier/components/AppSettings")),
|
||||
};
|
||||
|
||||
export const AppSettings = (props: { slug: string }) => {
|
||||
return <DynamicComponent<typeof AppSettingsMap> componentMap={AppSettingsMap} {...props} />;
|
||||
return (
|
||||
<DynamicComponent<typeof AppSettingsComponentsMap> componentMap={AppSettingsComponentsMap} {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -29,6 +29,10 @@ export const InstallAppButtonMap = {
|
||||
zapier: dynamic(() => import("./zapier/components/InstallAppButton")),
|
||||
zoomvideo: dynamic(() => import("./zoomvideo/components/InstallAppButton")),
|
||||
};
|
||||
export const AppSettingsComponentsMap = {
|
||||
weather_in_your_calendar: dynamic(() => import("./weather_in_your_calendar/components/AppSettings")),
|
||||
zapier: dynamic(() => import("./zapier/components/AppSettings")),
|
||||
};
|
||||
export const EventTypeAddonMap = {
|
||||
fathom: dynamic(() => import("./fathom/extensions/EventTypeAppCard")),
|
||||
giphy: dynamic(() => import("./giphy/extensions/EventTypeAppCard")),
|
||||
|
||||
@@ -32,6 +32,7 @@ import { metadata as stripepayment_meta } from "./stripepayment/_metadata";
|
||||
import { metadata as tandemvideo_meta } from "./tandemvideo/_metadata";
|
||||
import { metadata as typeform_meta } from "./typeform/_metadata";
|
||||
import { metadata as vital_meta } from "./vital/_metadata";
|
||||
import { metadata as weather_in_your_calendar_meta } from "./weather_in_your_calendar/_metadata";
|
||||
import { metadata as whereby_meta } from "./whereby/_metadata";
|
||||
import { metadata as wipemycalother_meta } from "./wipemycalother/_metadata";
|
||||
import { metadata as zapier_meta } from "./zapier/_metadata";
|
||||
@@ -68,6 +69,7 @@ export const appStoreMetadata = {
|
||||
tandemvideo: tandemvideo_meta,
|
||||
typeform: typeform_meta,
|
||||
vital: vital_meta,
|
||||
weather_in_your_calendar: weather_in_your_calendar_meta,
|
||||
whereby: whereby_meta,
|
||||
wipemycalother: wipemycalother_meta,
|
||||
zapier: zapier_meta,
|
||||
|
||||
@@ -31,6 +31,7 @@ export const apiHandlers = {
|
||||
tandemvideo: import("./tandemvideo/api"),
|
||||
typeform: import("./typeform/api"),
|
||||
vital: import("./vital/api"),
|
||||
weather_in_your_calendar: import("./weather_in_your_calendar/api"),
|
||||
whereby: import("./whereby/api"),
|
||||
wipemycalother: import("./wipemycalother/api"),
|
||||
zapier: import("./zapier/api"),
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
items:
|
||||
- /api/app-store/weather_in_your_calendar/1.jpeg
|
||||
- /api/app-store/weather_in_your_calendar/2.jpeg
|
||||
---
|
||||
|
||||
<Slider items={items} />
|
||||
|
||||
You can now get the weather forecast directly into your calendar. This local weather calendar uses emojis ⛅️ 🌧️ ☀️ 🌨️ to display a 16 days forecast from OpenWeatherMap. Enter your city, adjust according to your preferences and subscribe to your calendar.
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { AppMeta } from "@calcom/types/App";
|
||||
|
||||
import config from "./config.json";
|
||||
|
||||
export const metadata = {
|
||||
category: "other",
|
||||
...config,
|
||||
} as AppMeta;
|
||||
|
||||
export default metadata;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { AppDeclarativeHandler } from "@calcom/types/AppHandler";
|
||||
|
||||
import { createDefaultInstallation } from "../../_utils/installation";
|
||||
import appConfig from "../config.json";
|
||||
|
||||
const handler: AppDeclarativeHandler = {
|
||||
// Instead of passing appType and slug from here, api/integrations/[..args] should be able to derive and pass these directly to createCredential
|
||||
appType: appConfig.type,
|
||||
variant: appConfig.variant,
|
||||
slug: appConfig.slug,
|
||||
supportsMultipleInstalls: false,
|
||||
handlerType: "add",
|
||||
createCredential: ({ appType, user, slug }) =>
|
||||
createDefaultInstallation({ appType, userId: user.id, slug, key: {} }),
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as add } from "./add";
|
||||
@@ -0,0 +1,38 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import Button from "@calcom/ui/v2/core/Button";
|
||||
import { TextField } from "@calcom/ui/v2/core/form/fields";
|
||||
|
||||
/*
|
||||
import * as Radio from "@calcom/ui/v2/core/form/radio-area/Radio";
|
||||
import { RadioField } from "@calcom/ui/v2/core/form/radio-area/Radio";
|
||||
*/
|
||||
|
||||
export default function AppSettings() {
|
||||
const { t } = useLocale();
|
||||
//const [units, setUnits] = useState<"metric" | "imperial">("metric");
|
||||
const unit = "metric";
|
||||
const [location, setLocation] = useState("");
|
||||
|
||||
return (
|
||||
<div className="space-y-4 px-4 pt-4 pb-4 text-sm">
|
||||
<TextField
|
||||
placeholder="San Francisco"
|
||||
value={location}
|
||||
name="Enter City"
|
||||
onChange={async (e) => {
|
||||
setLocation(e.target.value);
|
||||
}}
|
||||
/>
|
||||
{/* <Radio.Group onChange={(val) => alert(val)} aria-label="Set unit" defaultValue="metric">
|
||||
<RadioField label="°C Celsius" id="metric" value="metric" />
|
||||
<RadioField label="°F Fahrenheit" id="imperial" value="imperial" />
|
||||
</Radio.Group> */}
|
||||
<Button
|
||||
href={`webcal://weather-in-calendar.com/cal/weather-cal.php?city=${location}&units=${unit}&temperature=day`}>
|
||||
{t("add_to_calendar")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"/*": "Don't modify slug - If required, do it using cli edit command",
|
||||
"name": "Weather in your Calendar",
|
||||
"slug": "weather_in_your_calendar",
|
||||
"type": "weather_in_your_calendar_other",
|
||||
"imageSrc": "/api/app-store/weather_in_your_calendar/icon.gif",
|
||||
"logo": "/api/app-store/weather_in_your_calendar/icon.gif",
|
||||
"url": "https://weather-in-calendar.com",
|
||||
"variant": "other",
|
||||
"categories": ["other"],
|
||||
"publisher": "vejnoe",
|
||||
"email": "info@vejnoe.dk",
|
||||
"description": "Get the local weather forecast with icons in your calendar\r\r",
|
||||
"__createdUsingCli": true
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * as api from "./api";
|
||||
export { metadata } from "./_metadata";
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"name": "@calcom/weather_in_your_calendar",
|
||||
"version": "0.0.0",
|
||||
"main": "./index.ts",
|
||||
"description": "Get the local weather forecast with icons in your calendar\r\r",
|
||||
"dependencies": {
|
||||
"@calcom/lib": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@calcom/types": "*"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 812 KiB |
@@ -60,7 +60,7 @@ const templates: Template[] = [
|
||||
|
||||
export default function AppSettings() {
|
||||
return (
|
||||
<div className="grid gap-4 border-t border-gray-200 p-4 md:grid-cols-2">
|
||||
<div className="grid gap-4 p-4 md:grid-cols-2">
|
||||
{templates.map((template, index) => (
|
||||
<TemplateCard key={index} template={template} />
|
||||
))}
|
||||
|
||||
@@ -88,6 +88,12 @@
|
||||
"slug": "exchange",
|
||||
"type": "exchange_calendar"
|
||||
},
|
||||
{
|
||||
"dirName": "weather_in_your_calendar",
|
||||
"categories": ["other"],
|
||||
"slug": "weather_in_your_calendar",
|
||||
"type": "weather_in_your_calendar_other"
|
||||
},
|
||||
{
|
||||
"dirName": "fathom",
|
||||
"categories": ["analytics"],
|
||||
|
||||
Reference in New Issue
Block a user