mirror of
https://github.com/ForFarmTeam/ForFarm.git
synced 2025-12-19 14:04:08 +01:00
Merge branch 'feature-farm-setup' into feature-crop-management
This commit is contained in:
commit
e1ac5af5a6
@ -32,5 +32,5 @@ func (c *Cropland) Validate() error {
|
|||||||
type CroplandRepository interface {
|
type CroplandRepository interface {
|
||||||
GetByID(context.Context, string) (Cropland, error)
|
GetByID(context.Context, string) (Cropland, error)
|
||||||
CreateOrUpdate(context.Context, *Cropland) error
|
CreateOrUpdate(context.Context, *Cropland) error
|
||||||
// Delete(context.Context, string) error
|
Delete(context.Context, string) error
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,5 +29,5 @@ func (f *Farm) Validate() error {
|
|||||||
type FarmRepository interface {
|
type FarmRepository interface {
|
||||||
GetByID(context.Context, string) (Farm, error)
|
GetByID(context.Context, string) (Farm, error)
|
||||||
CreateOrUpdate(context.Context, *Farm) error
|
CreateOrUpdate(context.Context, *Farm) error
|
||||||
// Delete(context.Context, string) error
|
Delete(context.Context, string) error
|
||||||
}
|
}
|
||||||
|
|||||||
111
backend/internal/repository/postgres_cropland.go
Normal file
111
backend/internal/repository/postgres_cropland.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/forfarm/backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type postgresCroplandRepository struct {
|
||||||
|
conn Connection
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPostgresCropland(conn Connection) domain.CroplandRepository {
|
||||||
|
return &postgresCroplandRepository{conn: conn}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresCroplandRepository) fetch(ctx context.Context, query string, args ...interface{}) ([]domain.Cropland, error) {
|
||||||
|
rows, err := p.conn.Query(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var croplands []domain.Cropland
|
||||||
|
for rows.Next() {
|
||||||
|
var c domain.Cropland
|
||||||
|
if err := rows.Scan(
|
||||||
|
&c.UUID,
|
||||||
|
&c.Name,
|
||||||
|
&c.Status,
|
||||||
|
&c.Priority,
|
||||||
|
&c.LandSize,
|
||||||
|
&c.GrowthStage,
|
||||||
|
&c.PlantID,
|
||||||
|
&c.FarmID,
|
||||||
|
&c.CreatedAt,
|
||||||
|
&c.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
croplands = append(croplands, c)
|
||||||
|
}
|
||||||
|
return croplands, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresCroplandRepository) GetByID(ctx context.Context, uuid string) (domain.Cropland, error) {
|
||||||
|
query := `
|
||||||
|
SELECT uuid, name, status, priority, land_size, growth_stage, plant_id, farm_id, created_at, updated_at
|
||||||
|
FROM croplands
|
||||||
|
WHERE uuid = $1`
|
||||||
|
|
||||||
|
croplands, err := p.fetch(ctx, query, uuid)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Cropland{}, err
|
||||||
|
}
|
||||||
|
if len(croplands) == 0 {
|
||||||
|
return domain.Cropland{}, domain.ErrNotFound
|
||||||
|
}
|
||||||
|
return croplands[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresCroplandRepository) GetByFarmID(ctx context.Context, farmID string) ([]domain.Cropland, error) {
|
||||||
|
query := `
|
||||||
|
SELECT uuid, name, status, priority, land_size, growth_stage, plant_id, farm_id, created_at, updated_at
|
||||||
|
FROM croplands
|
||||||
|
WHERE farm_id = $1`
|
||||||
|
|
||||||
|
return p.fetch(ctx, query, farmID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresCroplandRepository) CreateOrUpdate(ctx context.Context, c *domain.Cropland) error {
|
||||||
|
if strings.TrimSpace(c.UUID) == "" {
|
||||||
|
c.UUID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
INSERT INTO croplands (uuid, name, status, priority, land_size, growth_stage, plant_id, farm_id, created_at, updated_at)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
|
||||||
|
ON CONFLICT (uuid) DO UPDATE
|
||||||
|
SET name = EXCLUDED.name,
|
||||||
|
status = EXCLUDED.status,
|
||||||
|
priority = EXCLUDED.priority,
|
||||||
|
land_size = EXCLUDED.land_size,
|
||||||
|
growth_stage = EXCLUDED.growth_stage,
|
||||||
|
plant_id = EXCLUDED.plant_id,
|
||||||
|
farm_id = EXCLUDED.farm_id,
|
||||||
|
updated_at = NOW()
|
||||||
|
RETURNING uuid, created_at, updated_at`
|
||||||
|
|
||||||
|
return p.conn.QueryRow(
|
||||||
|
ctx,
|
||||||
|
query,
|
||||||
|
c.UUID,
|
||||||
|
c.Name,
|
||||||
|
c.Status,
|
||||||
|
c.Priority,
|
||||||
|
c.LandSize,
|
||||||
|
c.GrowthStage,
|
||||||
|
c.PlantID,
|
||||||
|
c.FarmID,
|
||||||
|
).Scan(&c.CreatedAt, &c.UpdatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresCroplandRepository) Delete(ctx context.Context, uuid string) error {
|
||||||
|
query := `DELETE FROM croplands WHERE uuid = $1`
|
||||||
|
_, err := p.conn.Exec(ctx, query, uuid)
|
||||||
|
return err
|
||||||
|
}
|
||||||
102
backend/internal/repository/postgres_farm.go
Normal file
102
backend/internal/repository/postgres_farm.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/forfarm/backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type postgresFarmRepository struct {
|
||||||
|
conn Connection
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPostgresFarm(conn Connection) domain.FarmRepository {
|
||||||
|
return &postgresFarmRepository{conn: conn}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresFarmRepository) fetch(ctx context.Context, query string, args ...interface{}) ([]domain.Farm, error) {
|
||||||
|
rows, err := p.conn.Query(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var farms []domain.Farm
|
||||||
|
for rows.Next() {
|
||||||
|
var f domain.Farm
|
||||||
|
if err := rows.Scan(
|
||||||
|
&f.UUID,
|
||||||
|
&f.Name,
|
||||||
|
&f.Lat,
|
||||||
|
&f.Lon,
|
||||||
|
&f.CreatedAt,
|
||||||
|
&f.UpdatedAt,
|
||||||
|
&f.OwnerID,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
farms = append(farms, f)
|
||||||
|
}
|
||||||
|
return farms, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresFarmRepository) GetByID(ctx context.Context, uuid string) (domain.Farm, error) {
|
||||||
|
query := `
|
||||||
|
SELECT uuid, name, lat, lon, created_at, updated_at, owner_id
|
||||||
|
FROM farms
|
||||||
|
WHERE uuid = $1`
|
||||||
|
|
||||||
|
farms, err := p.fetch(ctx, query, uuid)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Farm{}, err
|
||||||
|
}
|
||||||
|
if len(farms) == 0 {
|
||||||
|
return domain.Farm{}, domain.ErrNotFound
|
||||||
|
}
|
||||||
|
return farms[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresFarmRepository) GetByOwnerID(ctx context.Context, ownerID string) ([]domain.Farm, error) {
|
||||||
|
query := `
|
||||||
|
SELECT uuid, name, lat, lon, created_at, updated_at, owner_id
|
||||||
|
FROM farms
|
||||||
|
WHERE owner_id = $1`
|
||||||
|
|
||||||
|
return p.fetch(ctx, query, ownerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresFarmRepository) CreateOrUpdate(ctx context.Context, f *domain.Farm) error {
|
||||||
|
if strings.TrimSpace(f.UUID) == "" {
|
||||||
|
f.UUID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `
|
||||||
|
INSERT INTO farms (uuid, name, lat, lon, created_at, updated_at, owner_id)
|
||||||
|
VALUES ($1, $2, $3, $4, NOW(), NOW(), $5)
|
||||||
|
ON CONFLICT (uuid) DO UPDATE
|
||||||
|
SET name = EXCLUDED.name,
|
||||||
|
lat = EXCLUDED.lat,
|
||||||
|
lon = EXCLUDED.lon,
|
||||||
|
updated_at = NOW(),
|
||||||
|
owner_id = EXCLUDED.owner_id
|
||||||
|
RETURNING uuid, created_at, updated_at`
|
||||||
|
|
||||||
|
return p.conn.QueryRow(
|
||||||
|
ctx,
|
||||||
|
query,
|
||||||
|
f.UUID,
|
||||||
|
f.Name,
|
||||||
|
f.Lat,
|
||||||
|
f.Lon,
|
||||||
|
f.OwnerID,
|
||||||
|
).Scan(&f.CreatedAt, &f.UpdatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *postgresFarmRepository) Delete(ctx context.Context, uuid string) error {
|
||||||
|
query := `DELETE FROM farms WHERE uuid = $1`
|
||||||
|
_, err := p.conn.Exec(ctx, query, uuid)
|
||||||
|
return err
|
||||||
|
}
|
||||||
67
frontend/app/setup/google-map-with-drawing.tsx
Normal file
67
frontend/app/setup/google-map-with-drawing.tsx
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { GoogleMap, LoadScript, DrawingManager } from "@react-google-maps/api";
|
||||||
|
import { useState, useCallback } from "react";
|
||||||
|
|
||||||
|
const containerStyle = {
|
||||||
|
width: "100%",
|
||||||
|
height: "500px",
|
||||||
|
};
|
||||||
|
|
||||||
|
const center = { lat: 13.7563, lng: 100.5018 }; // Example: Bangkok, Thailand
|
||||||
|
|
||||||
|
const GoogleMapWithDrawing = () => {
|
||||||
|
const [map, setMap] = useState<google.maps.Map | null>(null);
|
||||||
|
|
||||||
|
// Handles drawing complete
|
||||||
|
const onDrawingComplete = useCallback(
|
||||||
|
(overlay: google.maps.drawing.OverlayCompleteEvent) => {
|
||||||
|
console.log("Drawing complete:", overlay);
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadScript
|
||||||
|
googleMapsApiKey={process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY!}
|
||||||
|
libraries={["drawing"]}
|
||||||
|
>
|
||||||
|
<GoogleMap
|
||||||
|
mapContainerStyle={containerStyle}
|
||||||
|
center={center}
|
||||||
|
zoom={10}
|
||||||
|
onLoad={(map) => setMap(map)}
|
||||||
|
>
|
||||||
|
{map && (
|
||||||
|
<DrawingManager
|
||||||
|
onOverlayComplete={onDrawingComplete}
|
||||||
|
options={{
|
||||||
|
drawingControl: true,
|
||||||
|
drawingControlOptions: {
|
||||||
|
position: google.maps.ControlPosition.TOP_CENTER,
|
||||||
|
drawingModes: [
|
||||||
|
google.maps.drawing.OverlayType.POLYGON,
|
||||||
|
google.maps.drawing.OverlayType.RECTANGLE,
|
||||||
|
google.maps.drawing.OverlayType.CIRCLE,
|
||||||
|
google.maps.drawing.OverlayType.POLYLINE,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
polygonOptions: {
|
||||||
|
fillColor: "#FF0000",
|
||||||
|
fillOpacity: 0.5,
|
||||||
|
strokeWeight: 2,
|
||||||
|
},
|
||||||
|
rectangleOptions: {
|
||||||
|
fillColor: "#00FF00",
|
||||||
|
fillOpacity: 0.5,
|
||||||
|
strokeWeight: 2,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</GoogleMap>
|
||||||
|
</LoadScript>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GoogleMapWithDrawing;
|
||||||
230
frontend/app/setup/harvest-detail-form.tsx
Normal file
230
frontend/app/setup/harvest-detail-form.tsx
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import { harvestDetailsFormSchema } from "@/schemas/application.schema";
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
|
type harvestSchema = z.infer<typeof harvestDetailsFormSchema>;
|
||||||
|
|
||||||
|
export default function HarvestDetailsForm() {
|
||||||
|
const form = useForm<harvestSchema>({
|
||||||
|
resolver: zodResolver(harvestDetailsFormSchema),
|
||||||
|
defaultValues: {},
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<Form {...form}>
|
||||||
|
<form className="grid grid-cols-3 gap-5">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="daysToFlower"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Days To Flower
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
id="daysToFlower"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="daysToMaturity"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Days To Maturity
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
id="daysToMaturity"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="harvestWindow"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Harvest Window
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
id="harvestWindow"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="estimatedLossRate"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Estimated Loss Rate
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
id="estimatedLossRate"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="harvestUnits"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">Harvest Units</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
defaultValue={field.value}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-96">
|
||||||
|
<SelectValue placeholder="Select a harvest unit" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="bales">bales</SelectItem>
|
||||||
|
<SelectItem value="transplant">Transplant</SelectItem>
|
||||||
|
<SelectItem value="cutting">Cutting</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="estimatedRevenue"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Estimated Revenue
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
id="estimatedRevenue"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="expectedYieldPer100ft"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Expected Yield Per100ft
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
id="expectedYieldPer100ft"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="expectedYieldPerAcre"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Expected Yield Per Acre
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
id="expectedYieldPerAcre"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,14 +1,34 @@
|
|||||||
import PlantingDetailsForm from "./planting-detail-form";
|
import PlantingDetailsForm from "./planting-detail-form";
|
||||||
|
import HarvestDetailsForm from "./harvest-detail-form";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import GoogleMapWithDrawing from "./google-map-with-drawing";
|
||||||
|
|
||||||
export default function SetupPage() {
|
export default function SetupPage() {
|
||||||
return (
|
return (
|
||||||
<div className="p-5">
|
<div className="p-5">
|
||||||
<h1 className="text-2xl">Plating Details</h1>
|
<div className=" flex justify-center">
|
||||||
|
<h1 className="flex text-2xl ">Plating Details</h1>
|
||||||
|
</div>
|
||||||
<Separator className="mt-3" />
|
<Separator className="mt-3" />
|
||||||
<div className="mt-3">
|
<div className="mt-10 flex justify-center">
|
||||||
<PlantingDetailsForm />
|
<PlantingDetailsForm />
|
||||||
</div>
|
</div>
|
||||||
|
<div className=" flex justify-center mt-20">
|
||||||
|
<h1 className="flex text-2xl ">Harvest Details</h1>
|
||||||
|
</div>
|
||||||
|
<Separator className="mt-3" />
|
||||||
|
<div className="mt-10 flex justify-center">
|
||||||
|
<HarvestDetailsForm />
|
||||||
|
</div>
|
||||||
|
<div className="mt-10">
|
||||||
|
<div className=" flex justify-center mt-20">
|
||||||
|
<h1 className="flex text-2xl ">Map</h1>
|
||||||
|
</div>
|
||||||
|
<Separator className="mt-3" />
|
||||||
|
<div className="mt-10">
|
||||||
|
<GoogleMapWithDrawing />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,15 @@ import { useForm } from "react-hook-form";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
|
||||||
type plantingSchema = z.infer<typeof plantingDetailsFormSchema>;
|
type plantingSchema = z.infer<typeof plantingDetailsFormSchema>;
|
||||||
|
|
||||||
@ -23,7 +32,7 @@ export default function PlantingDetailsForm() {
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form className="space-y-8">
|
<form className="grid grid-cols-3 gap-5">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="daysToEmerge"
|
name="daysToEmerge"
|
||||||
@ -34,7 +43,7 @@ export default function PlantingDetailsForm() {
|
|||||||
<div className="mt-5 space-y-5">
|
<div className="mt-5 space-y-5">
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="number"
|
||||||
id="daysToEmerge"
|
id="daysToEmerge"
|
||||||
className="w-96"
|
className="w-96"
|
||||||
{...field}
|
{...field}
|
||||||
@ -56,7 +65,7 @@ export default function PlantingDetailsForm() {
|
|||||||
<div className="mt-5 space-y-5">
|
<div className="mt-5 space-y-5">
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="number"
|
||||||
id="plantSpacing"
|
id="plantSpacing"
|
||||||
className="w-96"
|
className="w-96"
|
||||||
{...field}
|
{...field}
|
||||||
@ -78,7 +87,7 @@ export default function PlantingDetailsForm() {
|
|||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="number"
|
||||||
id="rowSpacing"
|
id="rowSpacing"
|
||||||
className="w-96"
|
className="w-96"
|
||||||
{...field}
|
{...field}
|
||||||
@ -102,7 +111,7 @@ export default function PlantingDetailsForm() {
|
|||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="number"
|
||||||
id="plantingDepth"
|
id="plantingDepth"
|
||||||
className="w-96"
|
className="w-96"
|
||||||
{...field}
|
{...field}
|
||||||
@ -126,7 +135,7 @@ export default function PlantingDetailsForm() {
|
|||||||
<div className="mt-10 space-y-5">
|
<div className="mt-10 space-y-5">
|
||||||
<div className="flex space-x-5">
|
<div className="flex space-x-5">
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="number"
|
||||||
id="averageHeight"
|
id="averageHeight"
|
||||||
className="w-96"
|
className="w-96"
|
||||||
{...field}
|
{...field}
|
||||||
@ -138,6 +147,167 @@ export default function PlantingDetailsForm() {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="startMethod"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">Start Method</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
defaultValue={field.value}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-96">
|
||||||
|
<SelectValue placeholder="Select a start method" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="seed">Seed</SelectItem>
|
||||||
|
<SelectItem value="transplant">Transplant</SelectItem>
|
||||||
|
<SelectItem value="cutting">Cutting</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="lightProfile"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">Light Profile</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
defaultValue={field.value}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-96">
|
||||||
|
<SelectValue placeholder="Select light profile" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="xp">Seed</SelectItem>
|
||||||
|
<SelectItem value="xa">Transplant</SelectItem>
|
||||||
|
<SelectItem value="xz">Cutting</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="soilConditions"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Soil Conditions
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
defaultValue={field.value}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-96">
|
||||||
|
<SelectValue placeholder="Select a soil condition" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="xp">Seed</SelectItem>
|
||||||
|
<SelectItem value="xa">Transplant</SelectItem>
|
||||||
|
<SelectItem value="xz">Cutting</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="plantingDetails"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Planting Details
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Textarea
|
||||||
|
id="plantingDetails"
|
||||||
|
className="w-96"
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="pruningDetails"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="font-bold text-lg">
|
||||||
|
Pruning Details
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Textarea id="pruningDetails" className="w-96" {...field} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="isPerennial"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
aria-readonly
|
||||||
|
/>
|
||||||
|
<p>Plant is Perennial</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="isPerennial"
|
||||||
|
render={({ field }: { field: any }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<div className="mt-5 space-y-5">
|
||||||
|
<div className="flex space-x-5">
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
aria-readonly
|
||||||
|
/>
|
||||||
|
<p>Automatically create tasks for new plantings</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
159
frontend/components/ui/select.tsx
Normal file
159
frontend/components/ui/select.tsx
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||||
|
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Select = SelectPrimitive.Root
|
||||||
|
|
||||||
|
const SelectGroup = SelectPrimitive.Group
|
||||||
|
|
||||||
|
const SelectValue = SelectPrimitive.Value
|
||||||
|
|
||||||
|
const SelectTrigger = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<SelectPrimitive.Icon asChild>
|
||||||
|
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||||
|
</SelectPrimitive.Icon>
|
||||||
|
</SelectPrimitive.Trigger>
|
||||||
|
))
|
||||||
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||||
|
|
||||||
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollUpButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronUp className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollUpButton>
|
||||||
|
))
|
||||||
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
||||||
|
|
||||||
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.ScrollDownButton
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-default items-center justify-center py-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ScrollDownButton>
|
||||||
|
))
|
||||||
|
SelectScrollDownButton.displayName =
|
||||||
|
SelectPrimitive.ScrollDownButton.displayName
|
||||||
|
|
||||||
|
const SelectContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||||
|
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Portal>
|
||||||
|
<SelectPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
position === "popper" &&
|
||||||
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
position={position}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<SelectScrollUpButton />
|
||||||
|
<SelectPrimitive.Viewport
|
||||||
|
className={cn(
|
||||||
|
"p-1",
|
||||||
|
position === "popper" &&
|
||||||
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SelectPrimitive.Viewport>
|
||||||
|
<SelectScrollDownButton />
|
||||||
|
</SelectPrimitive.Content>
|
||||||
|
</SelectPrimitive.Portal>
|
||||||
|
))
|
||||||
|
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||||
|
|
||||||
|
const SelectLabel = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Label
|
||||||
|
ref={ref}
|
||||||
|
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||||
|
|
||||||
|
const SelectItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||||
|
>(({ className, children, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<SelectPrimitive.ItemIndicator>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
</SelectPrimitive.ItemIndicator>
|
||||||
|
</span>
|
||||||
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
|
</SelectPrimitive.Item>
|
||||||
|
))
|
||||||
|
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||||
|
|
||||||
|
const SelectSeparator = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SelectPrimitive.Separator
|
||||||
|
ref={ref}
|
||||||
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||||
|
|
||||||
|
export {
|
||||||
|
Select,
|
||||||
|
SelectGroup,
|
||||||
|
SelectValue,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectContent,
|
||||||
|
SelectLabel,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectScrollUpButton,
|
||||||
|
SelectScrollDownButton,
|
||||||
|
}
|
||||||
29
frontend/components/ui/switch.tsx
Normal file
29
frontend/components/ui/switch.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Switch = React.forwardRef<
|
||||||
|
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<SwitchPrimitives.Root
|
||||||
|
className={cn(
|
||||||
|
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
>
|
||||||
|
<SwitchPrimitives.Thumb
|
||||||
|
className={cn(
|
||||||
|
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SwitchPrimitives.Root>
|
||||||
|
))
|
||||||
|
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||||
|
|
||||||
|
export { Switch }
|
||||||
22
frontend/components/ui/textarea.tsx
Normal file
22
frontend/components/ui/textarea.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const Textarea = React.forwardRef<
|
||||||
|
HTMLTextAreaElement,
|
||||||
|
React.ComponentProps<"textarea">
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
className={cn(
|
||||||
|
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
Textarea.displayName = "Textarea"
|
||||||
|
|
||||||
|
export { Textarea }
|
||||||
@ -15,9 +15,12 @@
|
|||||||
"@radix-ui/react-dialog": "^1.1.6",
|
"@radix-ui/react-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||||
"@radix-ui/react-label": "^2.1.2",
|
"@radix-ui/react-label": "^2.1.2",
|
||||||
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-separator": "^1.1.2",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.1.2",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
|
"@radix-ui/react-switch": "^1.1.3",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
|
"@react-google-maps/api": "^2.20.6",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@tanstack/react-query": "^5.66.0",
|
"@tanstack/react-query": "^5.66.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
|
|||||||
@ -23,15 +23,24 @@ dependencies:
|
|||||||
'@radix-ui/react-label':
|
'@radix-ui/react-label':
|
||||||
specifier: ^2.1.2
|
specifier: ^2.1.2
|
||||||
version: 2.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
version: 2.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-select':
|
||||||
|
specifier: ^2.1.6
|
||||||
|
version: 2.1.6(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
'@radix-ui/react-separator':
|
'@radix-ui/react-separator':
|
||||||
specifier: ^1.1.2
|
specifier: ^1.1.2
|
||||||
version: 1.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
version: 1.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
'@radix-ui/react-slot':
|
'@radix-ui/react-slot':
|
||||||
specifier: ^1.1.2
|
specifier: ^1.1.2
|
||||||
version: 1.1.2(@types/react@19.0.8)(react@19.0.0)
|
version: 1.1.2(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-switch':
|
||||||
|
specifier: ^1.1.3
|
||||||
|
version: 1.1.3(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
'@radix-ui/react-tooltip':
|
'@radix-ui/react-tooltip':
|
||||||
specifier: ^1.1.8
|
specifier: ^1.1.8
|
||||||
version: 1.1.8(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
version: 1.1.8(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@react-google-maps/api':
|
||||||
|
specifier: ^2.20.6
|
||||||
|
version: 2.20.6(react-dom@19.0.0)(react@19.0.0)
|
||||||
'@tailwindcss/typography':
|
'@tailwindcss/typography':
|
||||||
specifier: ^0.5.16
|
specifier: ^0.5.16
|
||||||
version: 0.5.16(tailwindcss@3.4.17)
|
version: 0.5.16(tailwindcss@3.4.17)
|
||||||
@ -218,6 +227,17 @@ packages:
|
|||||||
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@googlemaps/js-api-loader@1.16.8:
|
||||||
|
resolution: {integrity: sha512-CROqqwfKotdO6EBjZO/gQGVTbeDps5V7Mt9+8+5Q+jTg5CRMi3Ii/L9PmV3USROrt2uWxtGzJHORmByxyo9pSQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@googlemaps/markerclusterer@2.5.3:
|
||||||
|
resolution: {integrity: sha512-x7lX0R5yYOoiNectr10wLgCBasNcXFHiADIBdmn7jQllF2B5ENQw5XtZK+hIw4xnV0Df0xhN4LN98XqA5jaiOw==}
|
||||||
|
dependencies:
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
supercluster: 8.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@hookform/resolvers@4.0.0(react-hook-form@7.54.2):
|
/@hookform/resolvers@4.0.0(react-hook-form@7.54.2):
|
||||||
resolution: {integrity: sha512-93ZueVlTaeMF0pRbrLbcnzrxeb2mGA/xyO3RgfrsKs5OCtcfjoWcdjBJm+N7096Jfg/JYlGPjuyQCgqVEodSTg==}
|
resolution: {integrity: sha512-93ZueVlTaeMF0pRbrLbcnzrxeb2mGA/xyO3RgfrsKs5OCtcfjoWcdjBJm+N7096Jfg/JYlGPjuyQCgqVEodSTg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -581,6 +601,10 @@ packages:
|
|||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
/@radix-ui/number@1.1.0:
|
||||||
|
resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/primitive@1.1.1:
|
/@radix-ui/primitive@1.1.1:
|
||||||
resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==}
|
resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==}
|
||||||
dev: false
|
dev: false
|
||||||
@ -1025,6 +1049,46 @@ packages:
|
|||||||
react-dom: 19.0.0(react@19.0.0)
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-select@2.1.6(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0):
|
||||||
|
resolution: {integrity: sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@radix-ui/number': 1.1.0
|
||||||
|
'@radix-ui/primitive': 1.1.1
|
||||||
|
'@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-context': 1.1.1(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-direction': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-id': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-slot': 1.1.2(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@types/react': 19.0.8
|
||||||
|
'@types/react-dom': 19.0.3(@types/react@19.0.8)
|
||||||
|
aria-hidden: 1.2.4
|
||||||
|
react: 19.0.0
|
||||||
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
react-remove-scroll: 2.6.3(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-separator@1.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0):
|
/@radix-ui/react-separator@1.1.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0):
|
||||||
resolution: {integrity: sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==}
|
resolution: {integrity: sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1059,6 +1123,32 @@ packages:
|
|||||||
react: 19.0.0
|
react: 19.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-switch@1.1.3(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0):
|
||||||
|
resolution: {integrity: sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@radix-ui/primitive': 1.1.1
|
||||||
|
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-context': 1.1.1(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@radix-ui/react-use-size': 1.1.0(@types/react@19.0.8)(react@19.0.0)
|
||||||
|
'@types/react': 19.0.8
|
||||||
|
'@types/react-dom': 19.0.3(@types/react@19.0.8)
|
||||||
|
react: 19.0.0
|
||||||
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-tooltip@1.1.8(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0):
|
/@radix-ui/react-tooltip@1.1.8(@types/react-dom@19.0.3)(@types/react@19.0.8)(react-dom@19.0.0)(react@19.0.0):
|
||||||
resolution: {integrity: sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==}
|
resolution: {integrity: sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1209,6 +1299,30 @@ packages:
|
|||||||
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@react-google-maps/api@2.20.6(react-dom@19.0.0)(react@19.0.0):
|
||||||
|
resolution: {integrity: sha512-frxkSHWbd36ayyxrEVopSCDSgJUT1tVKXvQld2IyzU3UnDuqqNA3AZE4/fCdqQb2/zBQx3nrWnZB1wBXDcrjcw==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8 || ^17 || ^18 || ^19
|
||||||
|
react-dom: ^16.8 || ^17 || ^18 || ^19
|
||||||
|
dependencies:
|
||||||
|
'@googlemaps/js-api-loader': 1.16.8
|
||||||
|
'@googlemaps/markerclusterer': 2.5.3
|
||||||
|
'@react-google-maps/infobox': 2.20.0
|
||||||
|
'@react-google-maps/marker-clusterer': 2.20.0
|
||||||
|
'@types/google.maps': 3.58.1
|
||||||
|
invariant: 2.2.4
|
||||||
|
react: 19.0.0
|
||||||
|
react-dom: 19.0.0(react@19.0.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@react-google-maps/infobox@2.20.0:
|
||||||
|
resolution: {integrity: sha512-03PJHjohhaVLkX6+NHhlr8CIlvUxWaXhryqDjyaZ8iIqqix/nV8GFdz9O3m5OsjtxtNho09F/15j14yV0nuyLQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@react-google-maps/marker-clusterer@2.20.0:
|
||||||
|
resolution: {integrity: sha512-tieX9Va5w1yP88vMgfH1pHTacDQ9TgDTjox3tLlisKDXRQWdjw+QeVVghhf5XqqIxXHgPdcGwBvKY6UP+SIvLw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@rtsao/scc@1.1.0:
|
/@rtsao/scc@1.1.0:
|
||||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -1256,6 +1370,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/google.maps@3.58.1:
|
||||||
|
resolution: {integrity: sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/json-schema@7.0.15:
|
/@types/json-schema@7.0.15:
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -2287,7 +2405,6 @@ packages:
|
|||||||
|
|
||||||
/fast-deep-equal@3.1.3:
|
/fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/fast-glob@3.3.1:
|
/fast-glob@3.3.1:
|
||||||
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
|
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
|
||||||
@ -2557,6 +2674,12 @@ packages:
|
|||||||
side-channel: 1.1.0
|
side-channel: 1.1.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/invariant@2.2.4:
|
||||||
|
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-array-buffer@3.0.5:
|
/is-array-buffer@3.0.5:
|
||||||
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
|
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -2784,7 +2907,6 @@ packages:
|
|||||||
|
|
||||||
/js-tokens@4.0.0:
|
/js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/js-yaml@4.1.0:
|
/js-yaml@4.1.0:
|
||||||
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
||||||
@ -2822,6 +2944,10 @@ packages:
|
|||||||
object.values: 1.2.1
|
object.values: 1.2.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/kdbush@4.0.2:
|
||||||
|
resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/keyv@4.5.4:
|
/keyv@4.5.4:
|
||||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2877,7 +3003,6 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
js-tokens: 4.0.0
|
js-tokens: 4.0.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/lru-cache@10.4.3:
|
/lru-cache@10.4.3:
|
||||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||||
@ -3723,6 +3848,12 @@ packages:
|
|||||||
pirates: 4.0.6
|
pirates: 4.0.6
|
||||||
ts-interface-checker: 0.1.13
|
ts-interface-checker: 0.1.13
|
||||||
|
|
||||||
|
/supercluster@8.0.1:
|
||||||
|
resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==}
|
||||||
|
dependencies:
|
||||||
|
kdbush: 4.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/supports-color@7.2.0:
|
/supports-color@7.2.0:
|
||||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user