mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 10:19:51 -06:00
Add close on date functionality for surveys (#463)
* added date-picker * added state and handlers for closeOnDate * closeDate -> closeOnDate * added endpoint for CRON to close surveys * resolved migrations * fixed datetime format * removed warnings * PR review changes * resolved merge conflicts and package update * add github workflow for cron * change migration order * change migration order * add zod types for closeOnDate --------- Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
@@ -97,4 +97,7 @@ GITHUB_SECRET=
|
||||
# Configure Google Login
|
||||
NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=0
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
|
||||
# Cron Secret
|
||||
CRON_SECRET=
|
||||
@@ -105,4 +105,4 @@ NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=
|
||||
NEXT_PUBLIC_FORMBRICKS_ONBOARDING_SURVEY_ID=
|
||||
|
||||
# Cron Secret
|
||||
CRON_SECRET=
|
||||
CRON_SECRET=
|
||||
|
||||
23
.github/workflows/cron-closeOnDate.yml
vendored
Normal file
23
.github/workflows/cron-closeOnDate.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Cron - weeklySummary
|
||||
|
||||
on:
|
||||
# "Scheduled workflows run on the latest commit on the default or base branch."
|
||||
# — https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#schedule
|
||||
schedule:
|
||||
# Runs “At 00:00.” (see https://crontab.guru)
|
||||
- cron: "0 0 * * *"
|
||||
jobs:
|
||||
cron-weeklySummary:
|
||||
env:
|
||||
APP_URL: ${{ secrets.APP_URL }}
|
||||
CRON_API_KEY: ${{ secrets.CRON_SECRET }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: cURL request
|
||||
if: ${{ env.APP_URL && env.CRON_SECRET }}
|
||||
run: |
|
||||
curl ${{ secrets.APP_URL }}/api/cron/close_surveys \
|
||||
-X POST \
|
||||
-H 'content-type: application/json' \
|
||||
-H 'authorization: ${{ secrets.CRON_SECRET }}' \
|
||||
--fail
|
||||
@@ -13,7 +13,7 @@ export const meta = {
|
||||
description="Add a new webhook."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
label: "x-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
@@ -82,7 +82,7 @@ export const meta = {
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@ export const meta = {
|
||||
description="Delete a specific webhook by its ID."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
label: "x-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
@@ -45,7 +45,7 @@ export const meta = {
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@ export const meta = {
|
||||
description="Retrieve a specific webhook by its ID."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
label: "x-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
@@ -45,7 +45,7 @@ export const meta = {
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@ export const meta = {
|
||||
description="Retrieve a list of all webhooks."
|
||||
headers={[
|
||||
{
|
||||
label: "X-Api-Key",
|
||||
label: "x-Api-Key",
|
||||
type: "string",
|
||||
description: "Your Formbricks API key.",
|
||||
required: true,
|
||||
@@ -47,7 +47,7 @@ export const meta = {
|
||||
"code": "not_authenticated",
|
||||
"message": "Not authenticated",
|
||||
"details": {
|
||||
"X-Api-Key": "Header not provided or API Key invalid"
|
||||
"x-Api-Key": "Header not provided or API Key invalid"
|
||||
}
|
||||
}`,
|
||||
},
|
||||
|
||||
43
apps/web/app/api/cron/close_surveys/route.ts
Normal file
43
apps/web/app/api/cron/close_surveys/route.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { headers } from "next/headers";
|
||||
import { prisma } from "@formbricks/database";
|
||||
|
||||
export async function POST() {
|
||||
const headersList = headers();
|
||||
const apiKey = headersList.get("x-api-key");
|
||||
|
||||
if (!apiKey || apiKey !== process.env.CRON_SECRET) {
|
||||
return responses.notAuthenticatedResponse();
|
||||
}
|
||||
|
||||
const surveys = await prisma.survey.findMany({
|
||||
where: {
|
||||
status: "inProgress",
|
||||
closeOnDate: {
|
||||
lte: new Date(),
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!surveys.length) {
|
||||
return responses.successResponse({ message: "No surveys to close" });
|
||||
}
|
||||
|
||||
const mutationResp = await prisma.survey.updateMany({
|
||||
where: {
|
||||
id: {
|
||||
in: surveys.map((survey) => survey.id),
|
||||
},
|
||||
},
|
||||
data: {
|
||||
status: "completed",
|
||||
},
|
||||
});
|
||||
|
||||
return responses.successResponse({
|
||||
message: `Closed ${mutationResp.count} survey(s)`,
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import type { Survey } from "@formbricks/types/surveys";
|
||||
import { Input, Label, Switch } from "@formbricks/ui";
|
||||
import { Input, Label, Switch, DatePicker } from "@formbricks/ui";
|
||||
import { CheckCircleIcon } from "@heroicons/react/24/solid";
|
||||
import * as Collapsible from "@radix-ui/react-collapsible";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -15,7 +15,10 @@ export default function ResponseOptionsCard({ localSurvey, setLocalSurvey }: Res
|
||||
const [open, setOpen] = useState(false);
|
||||
const autoComplete = localSurvey.autoComplete !== null;
|
||||
const [redirectToggle, setRedirectToggle] = useState(false);
|
||||
const [surveyCloseOnDateToggle, setSurveyCloseOnDateToggle] = useState(false);
|
||||
|
||||
const [redirectUrl, setRedirectUrl] = useState<string | null>("");
|
||||
const [closeOnDate, setCloseOnDate] = useState<Date>();
|
||||
|
||||
const handleRedirectCheckMark = () => {
|
||||
if (redirectToggle && localSurvey.redirectUrl) {
|
||||
@@ -31,17 +34,46 @@ export default function ResponseOptionsCard({ localSurvey, setLocalSurvey }: Res
|
||||
setRedirectToggle(true);
|
||||
};
|
||||
|
||||
const handleSurveyCloseOnDateToggle = () => {
|
||||
if (surveyCloseOnDateToggle && localSurvey.closeOnDate) {
|
||||
setSurveyCloseOnDateToggle(false);
|
||||
setCloseOnDate(undefined);
|
||||
setLocalSurvey({ ...localSurvey, closeOnDate: null });
|
||||
return;
|
||||
}
|
||||
|
||||
if (surveyCloseOnDateToggle) {
|
||||
setSurveyCloseOnDateToggle(false);
|
||||
return;
|
||||
}
|
||||
setSurveyCloseOnDateToggle(true);
|
||||
};
|
||||
|
||||
const handleRedirectUrlChange = (link: string) => {
|
||||
setRedirectUrl(link);
|
||||
setLocalSurvey({ ...localSurvey, redirectUrl: link });
|
||||
};
|
||||
|
||||
const handleCloseOnDateChange = (date: Date) => {
|
||||
const equivalentDate = date?.getDate();
|
||||
date?.setUTCHours(0, 0, 0, 0);
|
||||
date?.setDate(equivalentDate);
|
||||
|
||||
setCloseOnDate(date);
|
||||
setLocalSurvey({ ...localSurvey, closeOnDate: date ?? null });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (localSurvey.redirectUrl) {
|
||||
setRedirectUrl(localSurvey.redirectUrl);
|
||||
setRedirectToggle(true);
|
||||
}
|
||||
if (localSurvey.closeOnDate) {
|
||||
setCloseOnDate(localSurvey.closeOnDate);
|
||||
setSurveyCloseOnDateToggle(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleCheckMark = () => {
|
||||
if (autoComplete) {
|
||||
const updatedSurvey: Survey = { ...localSurvey, autoComplete: null };
|
||||
@@ -112,31 +144,54 @@ export default function ResponseOptionsCard({ localSurvey, setLocalSurvey }: Res
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{localSurvey.type === "link" && (
|
||||
<div className="p-3 ">
|
||||
<div className="ml-2 flex items-center space-x-1">
|
||||
<Switch id="redirectUrl" checked={redirectToggle} onCheckedChange={handleRedirectCheckMark} />
|
||||
<Label htmlFor="redirectUrl" className="cursor-pointer">
|
||||
<div className="ml-2">
|
||||
<h3 className="text-sm font-semibold text-slate-700">Redirect on completion</h3>
|
||||
<p className="text-xs font-normal text-slate-500">
|
||||
Redirect user to specified link on survey completion
|
||||
</p>
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
{redirectToggle && (
|
||||
<Input
|
||||
type="url"
|
||||
placeholder="https://www.example.com"
|
||||
value={redirectUrl ? redirectUrl : ""}
|
||||
onChange={(e) => handleRedirectUrlChange(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-3 ">
|
||||
<div className="ml-2 flex items-center space-x-1">
|
||||
<Switch id="redirectUrl" checked={redirectToggle} onCheckedChange={handleRedirectCheckMark} />
|
||||
<Label htmlFor="redirectUrl" className="cursor-pointer">
|
||||
<div className="ml-2">
|
||||
<h3 className="text-sm font-semibold text-slate-700">Redirect on completion</h3>
|
||||
<p className="text-xs font-normal text-slate-500">
|
||||
Redirect user to specified link on survey completion
|
||||
</p>
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
)}
|
||||
{redirectToggle && (
|
||||
<div className="mt-4">
|
||||
<Input
|
||||
type="url"
|
||||
placeholder="https://www.example.com"
|
||||
value={redirectUrl ? redirectUrl : ""}
|
||||
onChange={(e) => handleRedirectUrlChange(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="p-3 ">
|
||||
<div className="ml-2 flex items-center space-x-1">
|
||||
<Switch
|
||||
id="surveyDeadline"
|
||||
checked={surveyCloseOnDateToggle}
|
||||
onCheckedChange={handleSurveyCloseOnDateToggle}
|
||||
/>
|
||||
<Label htmlFor="surveyDeadline" className="cursor-pointer">
|
||||
<div className="ml-2">
|
||||
<h3 className="text-sm font-semibold text-slate-700">Close survey on date</h3>
|
||||
{localSurvey.status === "completed" && (
|
||||
<p className="text-xs font-normal text-slate-500">
|
||||
This form is already completed. You can change the status settings to make best use of
|
||||
this option.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Label>
|
||||
</div>
|
||||
{surveyCloseOnDateToggle && (
|
||||
<div className="mt-4">
|
||||
<DatePicker date={closeOnDate} handleDateChange={handleCloseOnDateChange} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Collapsible.CollapsibleContent>
|
||||
</Collapsible.Root>
|
||||
|
||||
@@ -92,7 +92,7 @@ const notAuthenticatedResponse = (cors: boolean = false) =>
|
||||
code: "not_authenticated",
|
||||
message: "Not authenticated",
|
||||
details: {
|
||||
"X-Api-Key": "Header not provided or API Key invalid",
|
||||
"x-Api-Key": "Header not provided or API Key invalid",
|
||||
},
|
||||
} as ApiErrorResponse,
|
||||
{
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Survey" ADD COLUMN "closeOnDate" TIMESTAMP(3);
|
||||
@@ -236,6 +236,7 @@ model Survey {
|
||||
autoClose Int?
|
||||
delay Int @default(0)
|
||||
autoComplete Int?
|
||||
closeOnDate DateTime?
|
||||
}
|
||||
|
||||
model Event {
|
||||
|
||||
@@ -20,8 +20,10 @@ const selectSurvey = {
|
||||
displayOption: true,
|
||||
recontactDays: true,
|
||||
autoClose: true,
|
||||
closeOnDate: true,
|
||||
delay: true,
|
||||
autoComplete: true,
|
||||
closeOnDate: true,
|
||||
triggers: {
|
||||
select: {
|
||||
eventClass: {
|
||||
|
||||
@@ -26,6 +26,7 @@ export interface Survey {
|
||||
autoClose: number | null;
|
||||
delay: number;
|
||||
autoComplete: number | null;
|
||||
closeOnDate: Date | null;
|
||||
}
|
||||
|
||||
export interface AttributeFilter {
|
||||
|
||||
@@ -205,6 +205,7 @@ export const ZSurvey = z.object({
|
||||
thankYouCard: ZSurveyThankYouCard,
|
||||
delay: z.number(),
|
||||
autoComplete: z.union([z.number(), z.null()]),
|
||||
closeOnDate: z.date().nullable(),
|
||||
});
|
||||
|
||||
export type TSurvey = z.infer<typeof ZSurvey>;
|
||||
|
||||
55
packages/ui/components/Calendar.tsx
Normal file
55
packages/ui/components/Calendar.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { DayPicker } from "react-day-picker";
|
||||
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
// import { buttonVariants } from "@/components/ui/button";
|
||||
|
||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
||||
|
||||
function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
|
||||
return (
|
||||
<DayPicker
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn("p-3", className)}
|
||||
classNames={{
|
||||
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
||||
month: "space-y-4",
|
||||
caption: "flex justify-center pt-1 relative items-center",
|
||||
caption_label: "text-sm font-medium",
|
||||
nav: "space-x-1 flex items-center",
|
||||
nav_button: cn(
|
||||
"hover:text-slate-700 hover:bg-slate-200 flex justify-center items-center rounded-md transition-colors duration-150 ease-in-out h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
||||
),
|
||||
nav_button_previous: "absolute left-1",
|
||||
nav_button_next: "absolute right-1",
|
||||
table: "w-full border-collapse space-y-1",
|
||||
head_row: "flex",
|
||||
head_cell: "text-slate-500 rounded-md w-9 font-normal text-[0.8rem]",
|
||||
row: "flex w-full mt-2",
|
||||
cell: "text-center text-sm p-0 relative [&:has([aria-selected])]:bg-slate-200 first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
|
||||
day: cn("hover:bg-slate-200 rounded-md p-0", "h-9 w-9 p-0 font-normal aria-selected:opacity-100"),
|
||||
day_selected: "bg-black text-white aria-selected:bg-black aria-selected:text-white",
|
||||
day_today: "bg-slate-200 aria-selected:bg-black aria-selected:text-white",
|
||||
day_outside: "text-slate-500 opacity-50",
|
||||
day_disabled: "text-slate-500 opacity-50 cursor-not-allowed",
|
||||
day_range_middle: "aria-selected:bg-slate-200",
|
||||
day_hidden: "invisible",
|
||||
...classNames,
|
||||
}}
|
||||
disabled={{
|
||||
before: new Date(),
|
||||
}}
|
||||
components={{
|
||||
IconLeft: () => <ChevronLeft className="h-4 w-4" />,
|
||||
IconRight: () => <ChevronRight className="h-4 w-4" />,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Calendar.displayName = "Calendar";
|
||||
|
||||
export { Calendar };
|
||||
47
packages/ui/components/DatePicker.tsx
Normal file
47
packages/ui/components/DatePicker.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
"use client";
|
||||
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import { format } from "date-fns";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "./Popover";
|
||||
import Button from "./Button";
|
||||
import { Calendar } from "./Calendar";
|
||||
import { useRef } from "react";
|
||||
import { SelectSingleEventHandler } from "react-day-picker";
|
||||
|
||||
export function DatePicker({
|
||||
date,
|
||||
handleDateChange,
|
||||
}: {
|
||||
date?: Date;
|
||||
handleDateChange: (date?: Date) => void;
|
||||
}) {
|
||||
let formattedDate = date ? new Date(date) : undefined;
|
||||
|
||||
const btnRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
const handleDateSelect: SelectSingleEventHandler = (date) => {
|
||||
btnRef?.current?.click();
|
||||
handleDateChange(date);
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={"minimal"}
|
||||
className={cn(
|
||||
"w-[280px] justify-start border border-slate-300 text-left font-normal",
|
||||
!formattedDate && "text-muted-foreground"
|
||||
)}
|
||||
ref={btnRef}>
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{formattedDate ? format(formattedDate, "PPP") : <span>Pick a date</span>}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar mode="single" selected={formattedDate} onSelect={handleDateSelect} initialFocus />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -58,6 +58,8 @@ export {
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from "./components/Command";
|
||||
export { Calendar } from "./components/Calendar";
|
||||
export { DatePicker } from "./components/DatePicker";
|
||||
|
||||
/* Icons */
|
||||
export { AngryBirdRageIcon } from "./components/icons/AngryBirdRageIcon";
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
"next": "13.4.8",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-confetti": "^6.1.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-day-picker": "^8.8.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-radio-group": "^3.0.3",
|
||||
"react-use": "^17.4.0"
|
||||
}
|
||||
|
||||
71
pnpm-lock.yaml
generated
71
pnpm-lock.yaml
generated
@@ -1,4 +1,4 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
@@ -19,7 +19,7 @@ importers:
|
||||
version: 3.12.7
|
||||
turbo:
|
||||
specifier: latest
|
||||
version: 1.10.7
|
||||
version: 1.10.3
|
||||
|
||||
apps/demo:
|
||||
dependencies:
|
||||
@@ -349,7 +349,7 @@ importers:
|
||||
version: 8.8.0(eslint@8.41.0)
|
||||
eslint-config-turbo:
|
||||
specifier: latest
|
||||
version: 1.8.8(eslint@8.41.0)
|
||||
version: 1.10.3(eslint@8.41.0)
|
||||
eslint-plugin-react:
|
||||
specifier: 7.32.2
|
||||
version: 7.32.2(eslint@8.41.0)
|
||||
@@ -592,8 +592,11 @@ importers:
|
||||
react-confetti:
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0(react@18.2.0)
|
||||
react-day-picker:
|
||||
specifier: ^8.8.0
|
||||
version: 8.8.0(date-fns@2.30.0)(react@18.2.0)
|
||||
react-dom:
|
||||
specifier: 18.2.0
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
react-radio-group:
|
||||
specifier: ^3.0.3
|
||||
@@ -9536,13 +9539,13 @@ packages:
|
||||
eslint: 8.41.0
|
||||
dev: true
|
||||
|
||||
/eslint-config-turbo@1.8.8(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-+yT22sHOT5iC1sbBXfLIdXfbZuiv9bAyOXsxTxFCWelTeFFnANqmuKB3x274CFvf7WRuZ/vYP/VMjzU9xnFnxA==}
|
||||
/eslint-config-turbo@1.10.3(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-ggzPfTJfMsMS383oZ4zfTP1zQvyMyiigOQJRUnLt1nqII6SKkTzdKZdwmXRDHU24KFwUfEFtT6c8vnm2VhL0uQ==}
|
||||
peerDependencies:
|
||||
eslint: '>6.6.0'
|
||||
dependencies:
|
||||
eslint: 8.41.0
|
||||
eslint-plugin-turbo: 1.8.8(eslint@8.41.0)
|
||||
eslint-plugin-turbo: 1.10.3(eslint@8.41.0)
|
||||
dev: true
|
||||
|
||||
/eslint-import-resolver-node@0.3.6:
|
||||
@@ -9861,8 +9864,8 @@ packages:
|
||||
semver: 6.3.0
|
||||
string.prototype.matchall: 4.0.8
|
||||
|
||||
/eslint-plugin-turbo@1.8.8(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==}
|
||||
/eslint-plugin-turbo@1.10.3(eslint@8.41.0):
|
||||
resolution: {integrity: sha512-g3Mnnk7el1FqxHfqbE/MayLvCsYjA/vKmAnUj66kV4AlM7p/EZqdt42NMcMSKtDVEm0w+utQkkzWG2Xsa0Pd/g==}
|
||||
peerDependencies:
|
||||
eslint: '>6.6.0'
|
||||
dependencies:
|
||||
@@ -16714,6 +16717,16 @@ packages:
|
||||
tween-functions: 1.2.0
|
||||
dev: false
|
||||
|
||||
/react-day-picker@8.8.0(date-fns@2.30.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-QIC3uOuyGGbtypbd5QEggsCSqVaPNu8kzUWquZ7JjW9fuWB9yv7WyixKmnaFelTLXFdq7h7zU6n/aBleBqe/dA==}
|
||||
peerDependencies:
|
||||
date-fns: ^2.28.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
date-fns: 2.30.0
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-dom@18.2.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||
peerDependencies:
|
||||
@@ -19191,65 +19204,65 @@ packages:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
/turbo-darwin-64@1.10.7:
|
||||
resolution: {integrity: sha512-N2MNuhwrl6g7vGuz4y3fFG2aR1oCs0UZ5HKl8KSTn/VC2y2YIuLGedQ3OVbo0TfEvygAlF3QGAAKKtOCmGPNKA==}
|
||||
/turbo-darwin-64@1.10.3:
|
||||
resolution: {integrity: sha512-IIB9IomJGyD3EdpSscm7Ip1xVWtYb7D0x7oH3vad3gjFcjHJzDz9xZ/iw/qItFEW+wGFcLSRPd+1BNnuLM8AsA==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-darwin-arm64@1.10.7:
|
||||
resolution: {integrity: sha512-WbJkvjU+6qkngp7K4EsswOriO3xrNQag7YEGRtfLoDdMTk4O4QTeU6sfg2dKfDsBpTidTvEDwgIYJhYVGzrz9Q==}
|
||||
/turbo-darwin-arm64@1.10.3:
|
||||
resolution: {integrity: sha512-SBNmOZU9YEB0eyNIxeeQ+Wi0Ufd+nprEVp41rgUSRXEIpXjsDjyBnKnF+sQQj3+FLb4yyi/yZQckB+55qXWEsw==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-64@1.10.7:
|
||||
resolution: {integrity: sha512-x1CF2CDP1pDz/J8/B2T0hnmmOQI2+y11JGIzNP0KtwxDM7rmeg3DDTtDM/9PwGqfPotN9iVGgMiMvBuMFbsLhg==}
|
||||
/turbo-linux-64@1.10.3:
|
||||
resolution: {integrity: sha512-kvAisGKE7xHJdyMxZLvg53zvHxjqPK1UVj4757PQqtx9dnjYHSc8epmivE6niPgDHon5YqImzArCjVZJYpIGHQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-linux-arm64@1.10.7:
|
||||
resolution: {integrity: sha512-JtnBmaBSYbs7peJPkXzXxsRGSGBmBEIb6/kC8RRmyvPAMyqF8wIex0pttsI+9plghREiGPtRWv/lfQEPRlXnNQ==}
|
||||
/turbo-linux-arm64@1.10.3:
|
||||
resolution: {integrity: sha512-Qgaqln0IYRgyL0SowJOi+PNxejv1I2xhzXOI+D+z4YHbgSx87ox1IsALYBlK8VRVYY8VCXl+PN12r1ioV09j7A==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-64@1.10.7:
|
||||
resolution: {integrity: sha512-7A/4CByoHdolWS8dg3DPm99owfu1aY/W0V0+KxFd0o2JQMTQtoBgIMSvZesXaWM57z3OLsietFivDLQPuzE75w==}
|
||||
/turbo-windows-64@1.10.3:
|
||||
resolution: {integrity: sha512-rbH9wManURNN8mBnN/ZdkpUuTvyVVEMiUwFUX4GVE5qmV15iHtZfDLUSGGCP2UFBazHcpNHG1OJzgc55GFFrUw==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo-windows-arm64@1.10.7:
|
||||
resolution: {integrity: sha512-D36K/3b6+hqm9IBAymnuVgyePktwQ+F0lSXr2B9JfAdFPBktSqGmp50JNC7pahxhnuCLj0Vdpe9RqfnJw5zATA==}
|
||||
/turbo-windows-arm64@1.10.3:
|
||||
resolution: {integrity: sha512-ThlkqxhcGZX39CaTjsHqJnqVe+WImjX13pmjnpChz6q5HHbeRxaJSFzgrHIOt0sUUVx90W/WrNRyoIt/aafniw==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/turbo@1.10.7:
|
||||
resolution: {integrity: sha512-xm0MPM28TWx1e6TNC3wokfE5eaDqlfi0G24kmeHupDUZt5Wd0OzHFENEHMPqEaNKJ0I+AMObL6nbSZonZBV2HA==}
|
||||
/turbo@1.10.3:
|
||||
resolution: {integrity: sha512-U4gKCWcKgLcCjQd4Pl8KJdfEKumpyWbzRu75A6FCj6Ctea1PIm58W6Ltw1QXKqHrl2pF9e1raAskf/h6dlrPCA==}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
turbo-darwin-64: 1.10.7
|
||||
turbo-darwin-arm64: 1.10.7
|
||||
turbo-linux-64: 1.10.7
|
||||
turbo-linux-arm64: 1.10.7
|
||||
turbo-windows-64: 1.10.7
|
||||
turbo-windows-arm64: 1.10.7
|
||||
turbo-darwin-64: 1.10.3
|
||||
turbo-darwin-arm64: 1.10.3
|
||||
turbo-linux-64: 1.10.3
|
||||
turbo-linux-arm64: 1.10.3
|
||||
turbo-windows-64: 1.10.3
|
||||
turbo-windows-arm64: 1.10.3
|
||||
dev: true
|
||||
|
||||
/tween-functions@1.2.0:
|
||||
|
||||
Reference in New Issue
Block a user