From 8053e2bb4fee0fc548a991832984dd2547e901c0 Mon Sep 17 00:00:00 2001 From: samuraikun Date: Tue, 9 Jan 2024 20:49:17 -0800 Subject: [PATCH 01/15] wip: add func to upload file. --- app/trip/[id]/__test__/mock.ts | 4 +- app/trip/[id]/page.tsx | 53 ++++++++++++- app/trip/components/trip-card.tsx | 2 +- app/trip/graphql/query/tripDetails.graphql | 2 +- .../graphql/query/tripsCollection.graphql | 2 +- graphql-codegen/generated/api.ts | 64 ++++++++++++---- graphql-codegen/generated/gql.ts | 12 +-- graphql-codegen/generated/graphql.ts | 74 +++++++++++++------ .../generated/persisted-documents.json | 4 +- next.config.js | 13 +++- 10 files changed, 177 insertions(+), 53 deletions(-) diff --git a/app/trip/[id]/__test__/mock.ts b/app/trip/[id]/__test__/mock.ts index b172605..351199c 100644 --- a/app/trip/[id]/__test__/mock.ts +++ b/app/trip/[id]/__test__/mock.ts @@ -16,7 +16,7 @@ export const tripDetailsMock1 = [ { node: { id: 'trip-uuid-1', - image_storage_object_id: null, + image_url: null, title: 'Tokyo', date_from: '2021-01-01', date_to: '2021-01-01', @@ -109,7 +109,7 @@ export const tripDetailsMock2 = [ { node: { id: 'trip-uuid-2', - image_storage_object_id: null, + image_url: null, title: 'Tokyo', date_from: '2021-01-01', date_to: '2021-01-01', diff --git a/app/trip/[id]/page.tsx b/app/trip/[id]/page.tsx index 66768a4..ed41686 100644 --- a/app/trip/[id]/page.tsx +++ b/app/trip/[id]/page.tsx @@ -1,6 +1,8 @@ 'use client' -import { Box, Container, useColorModeValue } from '@chakra-ui/react' +import { useState } from 'react' +import { Box, Container, useColorModeValue, Input } from '@chakra-ui/react' +import { createClient } from '@supabase/supabase-js' import { useRouter } from 'next/navigation' import { PrimaryButton } from '@/components/button' import { Loading } from '@/components/loading' @@ -18,7 +20,11 @@ export default function TripDetailsPage({ const router = useRouter() - const { data: tripData, loading: tripLoading } = useTripDetailsQuery({ + const { + data: tripData, + loading: tripLoading, + refetch: refetchTrip + } = useTripDetailsQuery({ variables: { id: params.id } @@ -28,6 +34,37 @@ export default function TripDetailsPage({ const tripDataCollection = tripData?.tripsCollection + const [imageUrl, setImageUrl] = useState(null) + const uploadImage = async (id: string, file: File) => { + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_API_KEY! + ) + const { data, error } = await supabase.storage + .from('tabi-memo-uploads') + .upload(`trips/${id}/${file.name}`, file) + + if (error) { + throw error + } else { + console.log({ uploadFile: data }) + + // this approach needs two requests upload request -> get public url + const { + data: { publicUrl } + } = supabase.storage + .from(process.env.NEXT_PUBLIC_BUCKET_NAME!) + .getPublicUrl(data.path) + // const fileUrl = `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/${process.env.NEXT_PUBLIC_BUCKET_NAME}/${data.path}` + + // update trip image url if authorized by calling postgres function + // await supabase.rpc('update_trip_image', { trip_id: id, image_url: publicUrl }) + + setImageUrl(publicUrl) + refetchTrip() // Refetch trip after image upload + } + } + return ( <>
@@ -43,7 +80,7 @@ export default function TripDetailsPage({ <> Add Activity + { + if (e.target.files?.length) { + uploadImage(params.id, e.target.files[0]) + } + }} + /> )} diff --git a/app/trip/components/trip-card.tsx b/app/trip/components/trip-card.tsx index 6157790..df16931 100644 --- a/app/trip/components/trip-card.tsx +++ b/app/trip/components/trip-card.tsx @@ -47,7 +47,7 @@ export const TripCard = ({ data }: TripCardProps) => { > {`Picture cost?: Maybe id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe memo?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -503,11 +503,17 @@ export type ActivityEdge = { export type ActivityFilter = { address?: InputMaybe + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> time_from?: InputMaybe time_to?: InputMaybe title?: InputMaybe @@ -519,7 +525,7 @@ export type ActivityInsertInput = { address?: InputMaybe cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -540,7 +546,7 @@ export type ActivityOrderBy = { address?: InputMaybe cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -553,7 +559,7 @@ export type ActivityUpdateInput = { address?: InputMaybe cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -606,12 +612,18 @@ export type InvitationsEdge = { } export type InvitationsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> email?: InputMaybe id?: InputMaybe invitation_url?: InputMaybe invited_by_user_id?: InputMaybe invitee_user_id?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> permission_level?: InputMaybe trip_id?: InputMaybe } @@ -714,9 +726,15 @@ export type TagsEdge = { } export type TagsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> } export type TagsInsertInput = { @@ -845,8 +863,14 @@ export type Trip_TagsEdge = { } export type Trip_TagsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> id?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> tag_id?: InputMaybe trip_id?: InputMaybe } @@ -894,7 +918,7 @@ export type Trips = Node & { date_to?: Maybe description?: Maybe id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe invitationsCollection?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -952,14 +976,20 @@ export type TripsEdge = { } export type TripsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> cost?: InputMaybe created_at?: InputMaybe date_from?: InputMaybe date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> title?: InputMaybe user_id?: InputMaybe } @@ -971,7 +1001,7 @@ export type TripsInsertInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -991,7 +1021,7 @@ export type TripsOrderBy = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -1003,7 +1033,7 @@ export type TripsUpdateInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -1067,10 +1097,16 @@ export type UsersEdge = { } export type UsersFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> email?: InputMaybe id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> profile_picture_url?: InputMaybe } @@ -1190,7 +1226,7 @@ export type TripDetailsQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null invitationsCollection?: { __typename: 'invitationsConnection' edges: Array<{ @@ -1253,7 +1289,7 @@ export type TripsCollectionQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null created_at: string invitationsCollection?: { __typename: 'invitationsConnection' @@ -1545,7 +1581,7 @@ export const TripDetailsDocument = gql` title date_from date_to - image_storage_object_id + image_url invitationsCollection { __typename edges { @@ -1684,7 +1720,7 @@ export const TripsCollectionDocument = gql` title date_from date_to - image_storage_object_id + image_url created_at invitationsCollection { __typename diff --git a/graphql-codegen/generated/gql.ts b/graphql-codegen/generated/gql.ts index f4b387f..e100c4a 100644 --- a/graphql-codegen/generated/gql.ts +++ b/graphql-codegen/generated/gql.ts @@ -19,9 +19,9 @@ const documents = { types.ActivityCollectionDocument, 'mutation createTrip($user_id: UUID!, $title: String!, $date_from: Date, $date_to: Date) {\n insertIntotripsCollection(\n objects: [{user_id: $user_id, title: $title, date_from: $date_from, date_to: $date_to}]\n ) {\n records {\n __typename\n id\n title\n }\n }\n}': types.CreateTripDocument, - 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_storage_object_id\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}': + 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}': types.TripDetailsDocument, - 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_storage_object_id\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}': + 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_url\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}': types.TripsCollectionDocument } @@ -61,14 +61,14 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_storage_object_id\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}' -): (typeof documents)['query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_storage_object_id\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}'] + source: 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}' +): (typeof documents)['query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}'] /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_storage_object_id\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}' -): (typeof documents)['query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_storage_object_id\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}'] + source: 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_url\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}' +): (typeof documents)['query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_url\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}'] export function graphql(source: string) { return (documents as any)[source] ?? {} diff --git a/graphql-codegen/generated/graphql.ts b/graphql-codegen/generated/graphql.ts index 1ad1470..bf8aa9d 100644 --- a/graphql-codegen/generated/graphql.ts +++ b/graphql-codegen/generated/graphql.ts @@ -477,7 +477,7 @@ export type Activity = Node & { address?: Maybe cost?: Maybe id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe memo?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -511,11 +511,17 @@ export type ActivityEdge = { export type ActivityFilter = { address?: InputMaybe + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> time_from?: InputMaybe time_to?: InputMaybe title?: InputMaybe @@ -527,7 +533,7 @@ export type ActivityInsertInput = { address?: InputMaybe cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -548,7 +554,7 @@ export type ActivityOrderBy = { address?: InputMaybe cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -561,7 +567,7 @@ export type ActivityUpdateInput = { address?: InputMaybe cost?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -614,12 +620,18 @@ export type InvitationsEdge = { } export type InvitationsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> email?: InputMaybe id?: InputMaybe invitation_url?: InputMaybe invited_by_user_id?: InputMaybe invitee_user_id?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> permission_level?: InputMaybe trip_id?: InputMaybe } @@ -722,9 +734,15 @@ export type TagsEdge = { } export type TagsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> } export type TagsInsertInput = { @@ -853,8 +871,14 @@ export type Trip_TagsEdge = { } export type Trip_TagsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> id?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> tag_id?: InputMaybe trip_id?: InputMaybe } @@ -902,7 +926,7 @@ export type Trips = Node & { date_to?: Maybe description?: Maybe id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe invitationsCollection?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -960,14 +984,20 @@ export type TripsEdge = { } export type TripsFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> cost?: InputMaybe created_at?: InputMaybe date_from?: InputMaybe date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> title?: InputMaybe user_id?: InputMaybe } @@ -979,7 +1009,7 @@ export type TripsInsertInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -999,7 +1029,7 @@ export type TripsOrderBy = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -1011,7 +1041,7 @@ export type TripsUpdateInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -1075,10 +1105,16 @@ export type UsersEdge = { } export type UsersFilter = { + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> email?: InputMaybe id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> profile_picture_url?: InputMaybe } @@ -1198,7 +1234,7 @@ export type TripDetailsQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null invitationsCollection?: { __typename: 'invitationsConnection' edges: Array<{ @@ -1261,7 +1297,7 @@ export type TripsCollectionQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null created_at: string invitationsCollection?: { __typename: 'invitationsConnection' @@ -1674,7 +1710,7 @@ export const CreateTripDocument = { ] } as unknown as DocumentNode export const TripDetailsDocument = { - __meta__: { hash: '911f735030ae63fca4ef8cefcc3c07e92924ea00' }, + __meta__: { hash: '2d55b1c5b762fdef053cc44e3f34f33967afd7f8' }, kind: 'Document', definitions: [ { @@ -1768,10 +1804,7 @@ export const TripDetailsDocument = { }, { kind: 'Field', - name: { - kind: 'Name', - value: 'image_storage_object_id' - } + name: { kind: 'Name', value: 'image_url' } }, { kind: 'Field', @@ -2034,7 +2067,7 @@ export const TripDetailsDocument = { ] } as unknown as DocumentNode export const TripsCollectionDocument = { - __meta__: { hash: '70a61f873c23f1db13cef7cd265a9845e9bfc53e' }, + __meta__: { hash: '3256c7ff43134c13502c53f475e55fa91f55cabb' }, kind: 'Document', definitions: [ { @@ -2177,10 +2210,7 @@ export const TripsCollectionDocument = { }, { kind: 'Field', - name: { - kind: 'Name', - value: 'image_storage_object_id' - } + name: { kind: 'Name', value: 'image_url' } }, { kind: 'Field', diff --git a/graphql-codegen/generated/persisted-documents.json b/graphql-codegen/generated/persisted-documents.json index a3a76ec..89c1efb 100644 --- a/graphql-codegen/generated/persisted-documents.json +++ b/graphql-codegen/generated/persisted-documents.json @@ -2,6 +2,6 @@ "00c528b2b1c851c06119aedb1fba6b5c885713cf": "query getUser($id: UUID!) { __typename usersCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename email id name profile_picture_url } } } }", "2d419044f6b09dcfdf15e868fceccda14add69f4": "query activityCollection($id: UUID!) { __typename activityCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename address cost id image_storage_object_id memo time_from time_to title trip_id url } } } }", "995473133e320e5f7ef165df54d56100c62b3a75": "mutation createTrip($date_from: Date, $date_to: Date, $title: String!, $user_id: UUID!) { __typename insertIntotripsCollection( objects: [{user_id: $user_id, title: $title, date_from: $date_from, date_to: $date_to}] ) { __typename records { __typename id title } } }", - "911f735030ae63fca4ef8cefcc3c07e92924ea00": "query tripDetails($id: UUID!) { __typename tripsCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename address id time_from time_to title } } } date_from date_to id image_storage_object_id invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title trip_tagsCollection { __typename edges { __typename node { __typename tags { __typename id name } } } } } } } }", - "70a61f873c23f1db13cef7cd265a9845e9bfc53e": "query tripsCollection($after: Cursor, $filter: tripsFilter, $first: Int!, $orderBy: [tripsOrderBy!]) { __typename tripsCollection( filter: $filter first: $first after: $after orderBy: $orderBy ) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename id } } } created_at date_from date_to id id image_storage_object_id invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title } } pageInfo { __typename endCursor hasNextPage hasPreviousPage startCursor } } }" + "2d55b1c5b762fdef053cc44e3f34f33967afd7f8": "query tripDetails($id: UUID!) { __typename tripsCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename address id time_from time_to title } } } date_from date_to id image_url invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title trip_tagsCollection { __typename edges { __typename node { __typename tags { __typename id name } } } } } } } }", + "3256c7ff43134c13502c53f475e55fa91f55cabb": "query tripsCollection($after: Cursor, $filter: tripsFilter, $first: Int!, $orderBy: [tripsOrderBy!]) { __typename tripsCollection( filter: $filter first: $first after: $after orderBy: $orderBy ) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename id } } } created_at date_from date_to id id image_url invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title } } pageInfo { __typename endCursor hasNextPage hasPreviousPage startCursor } } }" } diff --git a/next.config.js b/next.config.js index 767719f..672e76f 100644 --- a/next.config.js +++ b/next.config.js @@ -1,4 +1,15 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {} +const nextConfig = { + images: { + remotePatterns: [ + { + protocol: 'http', + hostname: '127.0.0.1', + port: '54321', + pathname: '/storage/v1/object/public/**' + } + ] + } +} module.exports = nextConfig From 77a2dc844fd63d421aca2436cca6fa9d6186cf39 Mon Sep 17 00:00:00 2001 From: samuraikun Date: Sat, 20 Jan 2024 13:19:53 -0800 Subject: [PATCH 02/15] Refactor trip image upload and display --- app/trip/[id]/page.tsx | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/app/trip/[id]/page.tsx b/app/trip/[id]/page.tsx index ed41686..f149813 100644 --- a/app/trip/[id]/page.tsx +++ b/app/trip/[id]/page.tsx @@ -20,11 +20,7 @@ export default function TripDetailsPage({ const router = useRouter() - const { - data: tripData, - loading: tripLoading, - refetch: refetchTrip - } = useTripDetailsQuery({ + const { data: tripData, loading: tripLoading } = useTripDetailsQuery({ variables: { id: params.id } @@ -33,8 +29,7 @@ export default function TripDetailsPage({ if (!tripData && !tripLoading) throw new Error('No trip data found') const tripDataCollection = tripData?.tripsCollection - - const [imageUrl, setImageUrl] = useState(null) + const [selectedImage, setSelectedImage] = useState(null) const uploadImage = async (id: string, file: File) => { const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, @@ -42,26 +37,23 @@ export default function TripDetailsPage({ ) const { data, error } = await supabase.storage .from('tabi-memo-uploads') - .upload(`trips/${id}/${file.name}`, file) + .upload(`trips/${id}/${file.name}`, file, { upsert: true }) if (error) { throw error } else { - console.log({ uploadFile: data }) - - // this approach needs two requests upload request -> get public url const { data: { publicUrl } } = supabase.storage .from(process.env.NEXT_PUBLIC_BUCKET_NAME!) .getPublicUrl(data.path) - // const fileUrl = `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/${process.env.NEXT_PUBLIC_BUCKET_NAME}/${data.path}` - // update trip image url if authorized by calling postgres function - // await supabase.rpc('update_trip_image', { trip_id: id, image_url: publicUrl }) + await supabase + .from('trips') + .update({ image_url: publicUrl }) + .match({ id }) - setImageUrl(publicUrl) - refetchTrip() // Refetch trip after image upload + setSelectedImage(file) } } @@ -80,7 +72,11 @@ export default function TripDetailsPage({ <> Date: Sat, 20 Jan 2024 13:55:30 -0800 Subject: [PATCH 03/15] Add image refresh on trip detail page and trip list page after upload image. --- app/trip/[id]/page.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/trip/[id]/page.tsx b/app/trip/[id]/page.tsx index c885989..f441e65 100644 --- a/app/trip/[id]/page.tsx +++ b/app/trip/[id]/page.tsx @@ -19,7 +19,11 @@ export default function TripDetailsPage({ const router = useRouter() - const { data: tripData, loading: tripLoading } = useTripDetailsQuery({ + const { + data: tripData, + loading: tripLoading, + refetch: refetchTrip + } = useTripDetailsQuery({ variables: { id: params.id } @@ -53,6 +57,8 @@ export default function TripDetailsPage({ .match({ id }) setSelectedImage(file) + // NOTE: Refresh trip data to show new image on trip detail page and trip list page. + refetchTrip() } } From 03d96f1ea3d98dc97a50f3dd537a5fc93e794b62 Mon Sep 17 00:00:00 2001 From: samuraikun Date: Sat, 20 Jan 2024 19:27:21 -0800 Subject: [PATCH 04/15] fix: Refactoring upload impl using Server action. --- app/trip/[id]/action/upload-image.ts | 45 ++++++++++++++++++++++ app/trip/[id]/page.tsx | 46 ++++++++++------------- package.json | 1 + pnpm-lock.yaml | 56 +++++++++++++++------------- 4 files changed, 96 insertions(+), 52 deletions(-) create mode 100644 app/trip/[id]/action/upload-image.ts diff --git a/app/trip/[id]/action/upload-image.ts b/app/trip/[id]/action/upload-image.ts new file mode 100644 index 0000000..fdaab62 --- /dev/null +++ b/app/trip/[id]/action/upload-image.ts @@ -0,0 +1,45 @@ +'use server' +import { createServerActionClient } from '@supabase/auth-helpers-nextjs' +import { cookies } from 'next/headers' + +export const uploadImageAction = async ( + id: string, + filePath: string +): Promise< + | { status: 'success'; data: { publicUrl: string } } + | { status: 'error'; data: { publicUrl: string }; error: { message: string } } +> => { + try { + const cookieStore = cookies() + // NOTE: Use createServerActionClient instead of createClient in with-cookie.ts + // https://supabase.com/docs/guides/auth/auth-helpers/nextjs?language=ts#server-actions + const supabase = createServerActionClient({ cookies: () => cookieStore }) + + // Supabase Storage API is not available in the server action. + // const { data: uploadData, error: uploadError } = await supabase.storage + // .from('tabi-memo-uploads') + // .upload(`trips/${id}/${file.name}`, file, { upsert: true }) + + // if (uploadError) throw uploadError + + const { + data: { publicUrl } + } = await supabase.storage + .from(process.env.NEXT_PUBLIC_BUCKET_NAME!) + .getPublicUrl(filePath) + + const updateResponse = await supabase + .from('trips') + .update({ image_url: publicUrl }) + .match({ id }) + + if (updateResponse.error) { + return { status: 'error', data: { publicUrl }, error: { message: updateResponse.error.message } } + } + + return { status: 'success', data: { publicUrl } } + } catch (error) { + console.error({ error }) + return { status: 'error', data: { publicUrl: '' }, error: { message: 'Failed to upload image' } } + } +} diff --git a/app/trip/[id]/page.tsx b/app/trip/[id]/page.tsx index f441e65..3c323ba 100644 --- a/app/trip/[id]/page.tsx +++ b/app/trip/[id]/page.tsx @@ -6,6 +6,7 @@ import { createClient } from '@supabase/supabase-js' import { useRouter } from 'next/navigation' import { PrimaryButton } from '@/components/button' import { Loading } from '@/components/loading' +import { uploadImageAction } from './action/upload-image' import { TripDetailsHeader, TripDetailsTabs } from './components' import { useTripDetailsQuery } from '@generated/api' @@ -33,32 +34,29 @@ export default function TripDetailsPage({ const tripDataCollection = tripData?.tripsCollection const [selectedImage, setSelectedImage] = useState(null) + const uploadImage = async (id: string, file: File) => { - const supabase = createClient( - process.env.NEXT_PUBLIC_SUPABASE_URL!, - process.env.NEXT_PUBLIC_API_KEY! - ) - const { data, error } = await supabase.storage - .from('tabi-memo-uploads') - .upload(`trips/${id}/${file.name}`, file, { upsert: true }) + try { + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_API_KEY! + ) - if (error) { - throw error - } else { - const { - data: { publicUrl } - } = supabase.storage - .from(process.env.NEXT_PUBLIC_BUCKET_NAME!) - .getPublicUrl(data.path) + // TODO: Authenticated user can upload images with policy + const { data: uploadData, error: uploadError } = await supabase.storage + .from('tabi-memo-uploads') + .upload(`trips/${id}/${file.name}`, file, { upsert: true }) - await supabase - .from('trips') - .update({ image_url: publicUrl }) - .match({ id }) + if (uploadError) throw new Error(uploadError.message) + + // NOTE: Server action doen't return result in Client Component. I don't know why. + await uploadImageAction(id, uploadData.path) setSelectedImage(file) - // NOTE: Refresh trip data to show new image on trip detail page and trip list page. - refetchTrip() + await refetchTrip() + } catch (error) { + console.error({ error }) + throw error } } @@ -125,11 +123,7 @@ export default function TripDetailsPage({ type="file" id="imageUpload" accept="image/*" - onChange={(e) => { - if (e.target.files?.length) { - uploadImage(params.id, e.target.files[0]) - } - }} + onChange={(e) => uploadImage(params.id, e.target.files![0])} /> diff --git a/package.json b/package.json index 0dc97a4..fd4fa5e 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@graphql-codegen/client-preset": "^4.1.0", + "@supabase/auth-helpers-nextjs": "^0.8.7", "@types/jest": "^29.5.11", "framer-motion": "^10.16.4", "graphql": "^16.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7111f07..ffaddd2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ dependencies: '@graphql-codegen/client-preset': specifier: ^4.1.0 version: 4.1.0(graphql@16.8.1) + '@supabase/auth-helpers-nextjs': + specifier: ^0.8.7 + version: 0.8.7(@supabase/supabase-js@2.38.5) '@types/jest': specifier: ^29.5.11 version: 29.5.11 @@ -6638,30 +6641,45 @@ packages: resolve-from: 5.0.0 dev: true + /@supabase/auth-helpers-nextjs@0.8.7(@supabase/supabase-js@2.38.5): + resolution: {integrity: sha512-iYdOjFo0GkRvha340l8JdCiBiyXQuG9v8jnq7qMJ/2fakrskRgHTCOt7ryWbip1T6BExcWKC8SoJrhCzPOxhhg==} + peerDependencies: + '@supabase/supabase-js': ^2.19.0 + dependencies: + '@supabase/auth-helpers-shared': 0.6.3(@supabase/supabase-js@2.38.5) + '@supabase/supabase-js': 2.38.5 + set-cookie-parser: 2.6.0 + dev: false + + /@supabase/auth-helpers-shared@0.6.3(@supabase/supabase-js@2.38.5): + resolution: {integrity: sha512-xYQRLFeFkL4ZfwC7p9VKcarshj3FB2QJMgJPydvOY7J5czJe6xSG5/wM1z63RmAzGbCkKg+dzpq61oeSyWiGBQ==} + peerDependencies: + '@supabase/supabase-js': ^2.19.0 + dependencies: + '@supabase/supabase-js': 2.38.5 + jose: 4.15.4 + dev: false + /@supabase/functions-js@2.1.5: resolution: {integrity: sha512-BNzC5XhCzzCaggJ8s53DP+WeHHGT/NfTsx2wUSSGKR2/ikLFQTBCDzMvGz/PxYMqRko/LwncQtKXGOYp1PkPaw==} dependencies: '@supabase/node-fetch': 2.6.15 - dev: true /@supabase/gotrue-js@2.57.0: resolution: {integrity: sha512-/CcAW40aPKgp9/w9WgXVUQFg1AOdvFR687ONOMjASPBuC6FsNbKlcXp4pc+rwKNtxyxDkBbR+x7zj/8g00r/Og==} dependencies: '@supabase/node-fetch': 2.6.15 - dev: true /@supabase/node-fetch@2.6.15: resolution: {integrity: sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==} engines: {node: 4.x || >=6.0.0} dependencies: whatwg-url: 5.0.0 - dev: true /@supabase/postgrest-js@1.9.0: resolution: {integrity: sha512-axP6cU69jDrLbfihJKQ6vU27tklD0gzb9idkMN363MtTXeJVt5DQNT3JnJ58JVNBdL74hgm26rAsFNvHk+tnSw==} dependencies: '@supabase/node-fetch': 2.6.15 - dev: true /@supabase/realtime-js@2.8.4: resolution: {integrity: sha512-5C9slLTGikHnYmAnIBOaPogAgbcNY68vnIyE6GpqIKjHElVb6LIi4clwNcjHSj4z6szuvvzj8T/+ePEgGEGekw==} @@ -6672,7 +6690,6 @@ packages: websocket: 1.0.34 transitivePeerDependencies: - supports-color - dev: true /@supabase/ssr@0.0.10(@supabase/supabase-js@2.38.5): resolution: {integrity: sha512-eVs7+bNlff8Fd79x8K3Jbfpmf8P8QRA1Z6rUDN+fi4ReWvRBZyWOFfR6eqlsX6vTjvGgTiEqujFSkv2PYW5kbQ==} @@ -6688,7 +6705,6 @@ packages: resolution: {integrity: sha512-yspHD19I9uQUgfTh0J94+/r/g6hnhdQmw6Y7OWqr/EbnL6uvicGV1i1UDkkmeUHqfF9Mbt2sLtuxRycYyKv2ew==} dependencies: '@supabase/node-fetch': 2.6.15 - dev: true /@supabase/supabase-js@2.38.5: resolution: {integrity: sha512-QTXld3AfwAJgeOGyOKsCcT7AjC3jJxN02iHy299Fw+qKX0lJ1tVVhMGlga101C1stUCvgzjcypmMSGiZ2oeKsw==} @@ -6701,7 +6717,6 @@ packages: '@supabase/storage-js': 2.5.4 transitivePeerDependencies: - supports-color - dev: true /@swc/core-darwin-arm64@1.3.96: resolution: {integrity: sha512-8hzgXYVd85hfPh6mJ9yrG26rhgzCmcLO0h1TIl8U31hwmTbfZLzRitFQ/kqMJNbIBCwmNH1RU2QcJnL3d7f69A==} @@ -7163,7 +7178,6 @@ packages: /@types/phoenix@1.6.4: resolution: {integrity: sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA==} - dev: true /@types/pretty-hrtime@1.0.3: resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} @@ -7239,7 +7253,6 @@ packages: resolution: {integrity: sha512-svjGZvPB7EzuYS94cI7a+qhwgGU1y89wUgjT6E2wVUfmAGIvRfT7obBvRtnhXCSsoMdlG4gBFGE7MfkIXZLoww==} dependencies: '@types/node': 20.8.10 - dev: true /@types/ws@8.5.10: resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} @@ -8895,7 +8908,6 @@ packages: requiresBuild: true dependencies: node-gyp-build: 4.7.1 - dev: true /builtin-status-codes@3.0.0: resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} @@ -9706,7 +9718,6 @@ packages: dependencies: es5-ext: 0.10.62 type: 1.2.0 - dev: true /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -9738,7 +9749,6 @@ packages: optional: true dependencies: ms: 2.0.0 - dev: true /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -10346,7 +10356,6 @@ packages: es6-iterator: 2.0.3 es6-symbol: 3.1.3 next-tick: 1.1.0 - dev: true /es5-shim@4.6.7: resolution: {integrity: sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==} @@ -10359,7 +10368,6 @@ packages: d: 1.0.1 es5-ext: 0.10.62 es6-symbol: 3.1.3 - dev: true /es6-shim@0.35.8: resolution: {integrity: sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==} @@ -10370,7 +10378,6 @@ packages: dependencies: d: 1.0.1 ext: 1.7.0 - dev: true /esbuild-plugin-alias@0.2.1: resolution: {integrity: sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==} @@ -10897,7 +10904,6 @@ packages: resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} dependencies: type: 2.7.2 - dev: true /extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} @@ -12453,7 +12459,6 @@ packages: /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - dev: true /is-unc-path@1.0.0: resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} @@ -13097,6 +13102,10 @@ packages: hasBin: true dev: true + /jose@4.15.4: + resolution: {integrity: sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==} + dev: false + /jose@5.1.1: resolution: {integrity: sha512-bfB+lNxowY49LfrBO0ITUn93JbUhxUN8I11K6oI5hJu/G6PO6fEUddVLjqdD0cQ9SXIHWXuWh7eJYwZF7Z0N/g==} dev: true @@ -13882,7 +13891,6 @@ packages: /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -13940,7 +13948,6 @@ packages: /next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - dev: true /next@14.0.1(@babel/core@7.23.2)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-s4YaLpE4b0gmb3ggtmpmV+wt+lPRuGtANzojMQ2+gmBpgX9w5fTbjsy6dXByBuENsdCX5pukZH/GxdFgO62+pA==} @@ -14019,7 +14026,6 @@ packages: /node-gyp-build@4.7.1: resolution: {integrity: sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==} hasBin: true - dev: true /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -15980,6 +15986,10 @@ packages: /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + /set-cookie-parser@2.6.0: + resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} + dev: false + /set-function-length@1.1.1: resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} engines: {node: '>= 0.4'} @@ -17107,11 +17117,9 @@ packages: /type@1.2.0: resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} - dev: true /type@2.7.2: resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} - dev: true /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} @@ -17155,7 +17163,6 @@ packages: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: is-typedarray: 1.0.0 - dev: true /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} @@ -17428,7 +17435,6 @@ packages: requiresBuild: true dependencies: node-gyp-build: 4.7.1 - dev: true /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -17727,7 +17733,6 @@ packages: yaeti: 0.0.6 transitivePeerDependencies: - supports-color - dev: true /whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} @@ -17927,7 +17932,6 @@ packages: /yaeti@0.0.6: resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} engines: {node: '>=0.10.32'} - dev: true /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} From 6e159c0e8eb0475aa4f269faa23a57c0cc12f783 Mon Sep 17 00:00:00 2001 From: samuraikun Date: Sun, 21 Jan 2024 14:13:56 -0800 Subject: [PATCH 05/15] Rename server action --- .../[id]/action/{upload-image.ts => update-image-metadata.ts} | 2 +- app/trip/[id]/page.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename app/trip/[id]/action/{upload-image.ts => update-image-metadata.ts} (96%) diff --git a/app/trip/[id]/action/upload-image.ts b/app/trip/[id]/action/update-image-metadata.ts similarity index 96% rename from app/trip/[id]/action/upload-image.ts rename to app/trip/[id]/action/update-image-metadata.ts index fdaab62..c54bcfb 100644 --- a/app/trip/[id]/action/upload-image.ts +++ b/app/trip/[id]/action/update-image-metadata.ts @@ -2,7 +2,7 @@ import { createServerActionClient } from '@supabase/auth-helpers-nextjs' import { cookies } from 'next/headers' -export const uploadImageAction = async ( +export const updateImageMetadataAction = async ( id: string, filePath: string ): Promise< diff --git a/app/trip/[id]/page.tsx b/app/trip/[id]/page.tsx index 3c323ba..b7a7278 100644 --- a/app/trip/[id]/page.tsx +++ b/app/trip/[id]/page.tsx @@ -6,7 +6,7 @@ import { createClient } from '@supabase/supabase-js' import { useRouter } from 'next/navigation' import { PrimaryButton } from '@/components/button' import { Loading } from '@/components/loading' -import { uploadImageAction } from './action/upload-image' +import { updateImageMetadataAction } from './action/update-image-metadata' import { TripDetailsHeader, TripDetailsTabs } from './components' import { useTripDetailsQuery } from '@generated/api' @@ -50,7 +50,7 @@ export default function TripDetailsPage({ if (uploadError) throw new Error(uploadError.message) // NOTE: Server action doen't return result in Client Component. I don't know why. - await uploadImageAction(id, uploadData.path) + await updateImageMetadataAction(id, uploadData.path) setSelectedImage(file) await refetchTrip() From 602928a7520849c1e9ce24edfdfe82d4e3a3dc0c Mon Sep 17 00:00:00 2001 From: samuraikun Date: Wed, 31 Jan 2024 11:49:29 -0800 Subject: [PATCH 06/15] wip: add Mutation to create Activity --- .../graphql/mutation/createActivity.graphql | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 app/activity/create/graphql/mutation/createActivity.graphql diff --git a/app/activity/create/graphql/mutation/createActivity.graphql b/app/activity/create/graphql/mutation/createActivity.graphql new file mode 100644 index 0000000..2b31048 --- /dev/null +++ b/app/activity/create/graphql/mutation/createActivity.graphql @@ -0,0 +1,32 @@ +mutation createActivity( + $trip_id: UUID! + $title: String! + $time_from: Datetime + $time_to: Datetime + $address: String + $url: String + $memo: String + $cost: BigFloat +) { + insertIntoactivitiesCollection( + objects: [ + { + trip_id: $trip_id + title: $title + time_from: $time_from + time_to: $time_to + address: $address + url: $url + memo: $memo + cost: $cost + image_url: $image_url + } + ] + ) { + records { + __typename + id + title + } + } +} From 1dd11a8ea3af6e0d6569bf7e379c6bdd479e3d79 Mon Sep 17 00:00:00 2001 From: Sachi Goto <70562492+SachiGoto@users.noreply.github.com> Date: Fri, 2 Feb 2024 23:25:53 -0800 Subject: [PATCH 07/15] change password ui --- app/(auth)/change-password/page.tsx | 54 ++++++++++++++++++++++------- app/components/input/input-form.tsx | 19 ++++++++-- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/app/(auth)/change-password/page.tsx b/app/(auth)/change-password/page.tsx index 00088cf..5b2fa78 100644 --- a/app/(auth)/change-password/page.tsx +++ b/app/(auth)/change-password/page.tsx @@ -3,14 +3,14 @@ import { useState } from 'react' import { useForm } from 'react-hook-form' import { Box, - Flex, FormLabel, FormErrorMessage, FormControl, - Input, Heading, useToast, - useBoolean + useBoolean, + useColorModeValue, + VStack } from '@chakra-ui/react' import { useRouter } from 'next/navigation' import { @@ -18,8 +18,10 @@ import { ChangePasswordSchema } from '@/(auth)/change-password/schema' import { PrimaryButton } from '@/components/button' +import { InputForm } from '@/components/input' export default function ChangePassword() { + const color = useColorModeValue('black', 'gray.300') const toast = useToast() const [isLoading, setIsLoading] = useBoolean() const [toastId, setToastId] = useState | undefined>( @@ -63,27 +65,53 @@ export default function ChangePassword() { ) return ( - <> - Change Password - - + + + + Change Password + + Old Password - + {errors.oldPassword && ( {errors.oldPassword.message} )} New Password - + {errors.newPassword && ( {errors.newPassword.message} )} Confirm New Password - + {errors.confirmNewPassword && ( {errors.confirmNewPassword.message} @@ -93,8 +121,8 @@ export default function ChangePassword() { Change Password - - - + + + ) } diff --git a/app/components/input/input-form.tsx b/app/components/input/input-form.tsx index 237044f..e3b6e58 100644 --- a/app/components/input/input-form.tsx +++ b/app/components/input/input-form.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react' import { IconType } from 'react-icons' import { Input as ChakraFormInput, @@ -7,20 +8,24 @@ import { forwardRef, useColorModeValue } from '@chakra-ui/react' - +import { FiEye, FiEyeOff } from 'react-icons/fi' type InputFormProps = { rightIcon?: IconType + showInput?: boolean } export const InputForm = forwardRef( - ({ rightIcon: RightIcon, ...props }, ref) => { + ({ rightIcon: RightIcon, showInput, ...props }, ref) => { const bgColor = useColorModeValue('white', 'gray.700') const borderColor = useColorModeValue('gray.300', 'gray.500') const placeholdercolor = useColorModeValue('gray.400', 'gray.600') + const [show, setShow] = useState(false) + const handleClick = () => setShow(!show) return ( ( )} + + {showInput && ( + + {show ? : } + + )} ) } From 8ded231cfc5e63ddf249889580577940fe29b56c Mon Sep 17 00:00:00 2001 From: samuraikun Date: Sat, 3 Feb 2024 17:42:04 -0800 Subject: [PATCH 08/15] Replace image_storage_object_id to image_url. memo: Due to working app, this commit adjusts to the backend pull request of "https://github.com/tabi-memo/backend/pull/15" --- .../graphql/query/activityCollection.graphql | 3 +- .../graphql/mutation/createActivity.graphql | 6 +- app/trip/components/trip-form.tsx | 8 +- app/trip/graphql/query/tripDetails.graphql | 3 +- .../graphql/query/tripsCollection.graphql | 3 +- app/trip/hooks/useTripUpdate.ts | 2 +- app/trip/schema.ts | 2 +- graphql-codegen/generated/api.ts | 188 +++++++++++++-- graphql-codegen/generated/gql.ts | 24 +- graphql-codegen/generated/graphql.ts | 216 ++++++++++++++---- .../generated/persisted-documents.json | 8 +- 11 files changed, 371 insertions(+), 92 deletions(-) diff --git a/app/activity/[id]/graphql/query/activityCollection.graphql b/app/activity/[id]/graphql/query/activityCollection.graphql index 752b00a..1f9984e 100644 --- a/app/activity/[id]/graphql/query/activityCollection.graphql +++ b/app/activity/[id]/graphql/query/activityCollection.graphql @@ -11,7 +11,8 @@ query activityCollection($id: UUID!) { url memo cost - image_storage_object_id + cost_unit + image_url } } } diff --git a/app/activity/create/graphql/mutation/createActivity.graphql b/app/activity/create/graphql/mutation/createActivity.graphql index ed506ff..d77e189 100644 --- a/app/activity/create/graphql/mutation/createActivity.graphql +++ b/app/activity/create/graphql/mutation/createActivity.graphql @@ -8,8 +8,7 @@ mutation createActivity( $memo: String $cost: BigFloat $cost_unit: String - # $image_url: String // TODO ref: https://github.com/tabi-memo/frontend/pull/26 - $image_storage_object_id: UUID + $image_url: String ) { insertIntoactivityCollection( objects: [ @@ -23,8 +22,7 @@ mutation createActivity( memo: $memo cost: $cost cost_unit: $cost_unit - # image_url: $image_url // TODO ref: https://github.com/tabi-memo/frontend/pull/26 - image_storage_object_id: $image_storage_object_id + image_url: $image_url } ] ) { diff --git a/app/trip/components/trip-form.tsx b/app/trip/components/trip-form.tsx index bcf9112..a2f406a 100644 --- a/app/trip/components/trip-form.tsx +++ b/app/trip/components/trip-form.tsx @@ -80,7 +80,7 @@ export const TripForm = ({ tripDetails, tags, tripTags }: TripFormProps) => { ? getDateObj(tripDetails.dateFrom) : undefined, date_to: tripDetails?.dateTo ? getDateObj(tripDetails.dateTo) : null, - image_storage_object_id: tripDetails?.image || null, + image_url: tripDetails?.image || null, selectedTags: tripTags ? tripTags.data.map((tag) => tag.tag_id) : [], cost: tripDetails?.cost ? tripDetails.cost.toString() : null, cost_unit: tripDetails?.costUnit @@ -144,15 +144,13 @@ export const TripForm = ({ tripDetails, tags, tripTags }: TripFormProps) => { {/* TODO Image Upload to storage & Send the URL string to DB */} - + Image Select Image - - {errors?.image_storage_object_id?.message} - + {errors?.image_url?.message} diff --git a/app/trip/graphql/query/tripDetails.graphql b/app/trip/graphql/query/tripDetails.graphql index bf4aff7..38d8749 100644 --- a/app/trip/graphql/query/tripDetails.graphql +++ b/app/trip/graphql/query/tripDetails.graphql @@ -6,8 +6,7 @@ query tripDetails($id: UUID!) { title date_from date_to - # image_url // TODO ref: https://github.com/tabi-memo/frontend/pull/26 - image_storage_object_id + image_url cost cost_unit invitationsCollection { diff --git a/app/trip/graphql/query/tripsCollection.graphql b/app/trip/graphql/query/tripsCollection.graphql index 7df1938..b446d46 100644 --- a/app/trip/graphql/query/tripsCollection.graphql +++ b/app/trip/graphql/query/tripsCollection.graphql @@ -17,8 +17,7 @@ query tripsCollection( title date_from date_to - # image_url // TODO ref: https://github.com/tabi-memo/frontend/pull/26 - image_storage_object_id + image_url created_at invitationsCollection { edges { diff --git a/app/trip/hooks/useTripUpdate.ts b/app/trip/hooks/useTripUpdate.ts index cab109d..ca53209 100644 --- a/app/trip/hooks/useTripUpdate.ts +++ b/app/trip/hooks/useTripUpdate.ts @@ -38,7 +38,7 @@ export const useTripUpdate = ( title: data.title, date_from: formatToISODate(data.date_from), date_to: data.date_to ? formatToISODate(data.date_to) : null, - image_storage_object_id: data.image_storage_object_id, + image_url: data.image_url, cost: data.cost, cost_unit: data.cost_unit } diff --git a/app/trip/schema.ts b/app/trip/schema.ts index b220989..6b73ee7 100644 --- a/app/trip/schema.ts +++ b/app/trip/schema.ts @@ -8,7 +8,7 @@ const tripSchema = z.object({ invalid_type_error: "That's not a date" }), date_to: z.date().nullable(), - image_storage_object_id: z.string().nullable(), + image_url: z.string().nullable(), selectedTags: z.array(z.string()), cost: z.string().nullable(), cost_unit: z.string().nullable() diff --git a/graphql-codegen/generated/api.ts b/graphql-codegen/generated/api.ts index 2547f7d..2a80927 100644 --- a/graphql-codegen/generated/api.ts +++ b/graphql-codegen/generated/api.ts @@ -132,6 +132,8 @@ export type Mutation = { __typename?: 'Mutation' /** Deletes zero or more records from the `activity` collection */ deleteFromactivityCollection: ActivityDeleteResponse + /** Deletes zero or more records from the `activity_uploaded_files` collection */ + deleteFromactivity_uploaded_filesCollection: Activity_Uploaded_FilesDeleteResponse /** Deletes zero or more records from the `invitations` collection */ deleteFrominvitationsCollection: InvitationsDeleteResponse /** Deletes zero or more records from the `tags` collection */ @@ -144,6 +146,8 @@ export type Mutation = { deleteFromusersCollection: UsersDeleteResponse /** Adds one or more `activity` records to the collection */ insertIntoactivityCollection?: Maybe + /** Adds one or more `activity_uploaded_files` records to the collection */ + insertIntoactivity_uploaded_filesCollection?: Maybe /** Adds one or more `invitations` records to the collection */ insertIntoinvitationsCollection?: Maybe /** Adds one or more `tags` records to the collection */ @@ -156,6 +160,8 @@ export type Mutation = { insertIntousersCollection?: Maybe /** Updates zero or more records in the `activity` collection */ updateactivityCollection: ActivityUpdateResponse + /** Updates zero or more records in the `activity_uploaded_files` collection */ + updateactivity_uploaded_filesCollection: Activity_Uploaded_FilesUpdateResponse /** Updates zero or more records in the `invitations` collection */ updateinvitationsCollection: InvitationsUpdateResponse /** Updates zero or more records in the `tags` collection */ @@ -174,6 +180,12 @@ export type MutationDeleteFromactivityCollectionArgs = { filter?: InputMaybe } +/** The root type for creating and mutating data */ +export type MutationDeleteFromactivity_Uploaded_FilesCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe +} + /** The root type for creating and mutating data */ export type MutationDeleteFrominvitationsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -209,6 +221,11 @@ export type MutationInsertIntoactivityCollectionArgs = { objects: Array } +/** The root type for creating and mutating data */ +export type MutationInsertIntoactivity_Uploaded_FilesCollectionArgs = { + objects: Array +} + /** The root type for creating and mutating data */ export type MutationInsertIntoinvitationsCollectionArgs = { objects: Array @@ -241,6 +258,13 @@ export type MutationUpdateactivityCollectionArgs = { set: ActivityUpdateInput } +/** The root type for creating and mutating data */ +export type MutationUpdateactivity_Uploaded_FilesCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe + set: Activity_Uploaded_FilesUpdateInput +} + /** The root type for creating and mutating data */ export type MutationUpdateinvitationsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -312,6 +336,8 @@ export type Query = { __typename?: 'Query' /** A pagable collection of type `activity` */ activityCollection?: Maybe + /** A pagable collection of type `activity_uploaded_files` */ + activity_uploaded_filesCollection?: Maybe /** A pagable collection of type `invitations` */ invitationsCollection?: Maybe /** Retrieve a record by its `ID` */ @@ -336,6 +362,16 @@ export type QueryActivityCollectionArgs = { orderBy?: InputMaybe> } +/** The root type for querying data */ +export type QueryActivity_Uploaded_FilesCollectionArgs = { + after?: InputMaybe + before?: InputMaybe + filter?: InputMaybe + first?: InputMaybe + last?: InputMaybe + orderBy?: InputMaybe> +} + /** The root type for querying data */ export type QueryInvitationsCollectionArgs = { after?: InputMaybe @@ -430,11 +466,13 @@ export type UuidFilter = { export type Activity = Node & { __typename?: 'activity' + activity_uploaded_filesCollection?: Maybe address?: Maybe cost?: Maybe cost_unit?: Maybe + created_at: Scalars['Datetime']['output'] id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe memo?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -446,6 +484,15 @@ export type Activity = Node & { url?: Maybe } +export type ActivityActivity_Uploaded_FilesCollectionArgs = { + after?: InputMaybe + before?: InputMaybe + filter?: InputMaybe + first?: InputMaybe + last?: InputMaybe + orderBy?: InputMaybe> +} + export type ActivityConnection = { __typename?: 'activityConnection' edges: Array @@ -472,8 +519,9 @@ export type ActivityFilter = { and?: InputMaybe> cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe nodeId?: InputMaybe /** Negates a filter */ @@ -491,8 +539,9 @@ export type ActivityInsertInput = { address?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -513,8 +562,9 @@ export type ActivityOrderBy = { address?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -527,8 +577,9 @@ export type ActivityUpdateInput = { address?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -545,6 +596,101 @@ export type ActivityUpdateResponse = { records: Array } +export type Activity_Uploaded_Files = Node & { + __typename?: 'activity_uploaded_files' + activity?: Maybe + activity_id?: Maybe + content_type: Scalars['String']['output'] + created_at: Scalars['Datetime']['output'] + file_data?: Maybe + file_name: Scalars['String']['output'] + file_url: Scalars['String']['output'] + id: Scalars['UUID']['output'] + /** Globally Unique Record Identifier */ + nodeId: Scalars['ID']['output'] +} + +export type Activity_Uploaded_FilesConnection = { + __typename?: 'activity_uploaded_filesConnection' + edges: Array + pageInfo: PageInfo +} + +export type Activity_Uploaded_FilesDeleteResponse = { + __typename?: 'activity_uploaded_filesDeleteResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Activity_Uploaded_FilesEdge = { + __typename?: 'activity_uploaded_filesEdge' + cursor: Scalars['String']['output'] + node: Activity_Uploaded_Files +} + +export type Activity_Uploaded_FilesFilter = { + activity_id?: InputMaybe + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> + content_type?: InputMaybe + created_at?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe + nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> +} + +export type Activity_Uploaded_FilesInsertInput = { + activity_id?: InputMaybe + content_type?: InputMaybe + created_at?: InputMaybe + file_data?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe +} + +export type Activity_Uploaded_FilesInsertResponse = { + __typename?: 'activity_uploaded_filesInsertResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Activity_Uploaded_FilesOrderBy = { + activity_id?: InputMaybe + content_type?: InputMaybe + created_at?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe +} + +export type Activity_Uploaded_FilesUpdateInput = { + activity_id?: InputMaybe + content_type?: InputMaybe + created_at?: InputMaybe + file_data?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe +} + +export type Activity_Uploaded_FilesUpdateResponse = { + __typename?: 'activity_uploaded_filesUpdateResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + export type Invitations = Node & { __typename?: 'invitations' email: Scalars['String']['output'] @@ -836,7 +982,7 @@ export type Trips = Node & { date_to?: Maybe description?: Maybe id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe invitationsCollection?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -903,7 +1049,7 @@ export type TripsFilter = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe nodeId?: InputMaybe /** Negates a filter */ not?: InputMaybe @@ -921,7 +1067,7 @@ export type TripsInsertInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -942,7 +1088,7 @@ export type TripsOrderBy = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -955,7 +1101,7 @@ export type TripsUpdateInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -1121,7 +1267,8 @@ export type ActivityCollectionQuery = { url?: string | null memo?: string | null cost?: string | null - image_storage_object_id?: string | null + cost_unit?: string | null + image_url?: string | null } }> } | null @@ -1137,7 +1284,7 @@ export type CreateActivityMutationVariables = Exact<{ memo?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe }> export type CreateActivityMutation = { @@ -1259,7 +1406,7 @@ export type TripDetailsQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null cost?: string | null cost_unit?: string | null invitationsCollection?: { @@ -1344,7 +1491,7 @@ export type TripsCollectionQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null created_at: string invitationsCollection?: { __typename: 'invitationsConnection' @@ -1474,7 +1621,8 @@ export const ActivityCollectionDocument = gql` url memo cost - image_storage_object_id + cost_unit + image_url } } } @@ -1562,7 +1710,7 @@ export const CreateActivityDocument = gql` $memo: String $cost: BigFloat $cost_unit: String - $image_storage_object_id: UUID + $image_url: String ) { __typename insertIntoactivityCollection( @@ -1577,7 +1725,7 @@ export const CreateActivityDocument = gql` memo: $memo cost: $cost cost_unit: $cost_unit - image_storage_object_id: $image_storage_object_id + image_url: $image_url } ] ) { @@ -1617,7 +1765,7 @@ export type CreateActivityMutationFn = Apollo.MutationFunction< * memo: // value for 'memo' * cost: // value for 'cost' * cost_unit: // value for 'cost_unit' - * image_storage_object_id: // value for 'image_storage_object_id' + * image_url: // value for 'image_url' * }, * }); */ @@ -2082,7 +2230,7 @@ export const TripDetailsDocument = gql` title date_from date_to - image_storage_object_id + image_url cost cost_unit invitationsCollection { @@ -2311,7 +2459,7 @@ export const TripsCollectionDocument = gql` title date_from date_to - image_storage_object_id + image_url created_at invitationsCollection { __typename diff --git a/graphql-codegen/generated/gql.ts b/graphql-codegen/generated/gql.ts index 165d83a..5c1959e 100644 --- a/graphql-codegen/generated/gql.ts +++ b/graphql-codegen/generated/gql.ts @@ -15,9 +15,9 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- const documents = { 'query getUser($id: UUID!) {\n usersCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n email\n name\n profile_picture_url\n }\n }\n }\n}': types.GetUserDocument, - 'query activityCollection($id: UUID!) {\n activityCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n trip_id\n title\n time_from\n time_to\n address\n url\n memo\n cost\n image_storage_object_id\n }\n }\n }\n}': + 'query activityCollection($id: UUID!) {\n activityCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n trip_id\n title\n time_from\n time_to\n address\n url\n memo\n cost\n cost_unit\n image_url\n }\n }\n }\n}': types.ActivityCollectionDocument, - 'mutation createActivity($trip_id: UUID!, $title: String!, $time_from: Datetime, $time_to: Datetime, $address: String, $url: String, $memo: String, $cost: BigFloat, $cost_unit: String, $image_storage_object_id: UUID) {\n insertIntoactivityCollection(\n objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_storage_object_id: $image_storage_object_id}]\n ) {\n records {\n __typename\n id\n title\n }\n }\n}': + 'mutation createActivity($trip_id: UUID!, $title: String!, $time_from: Datetime, $time_to: Datetime, $address: String, $url: String, $memo: String, $cost: BigFloat, $cost_unit: String, $image_url: String) {\n insertIntoactivityCollection(\n objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_url: $image_url}]\n ) {\n records {\n __typename\n id\n title\n }\n }\n}': types.CreateActivityDocument, 'mutation createTag($name: String!, $userId: UUID!) {\n insertIntotagsCollection(objects: [{name: $name, user_id: $userId}]) {\n records {\n __typename\n id\n name\n }\n }\n}': types.CreateTagDocument, @@ -33,11 +33,11 @@ const documents = { types.UpdateTripDocument, 'query tagsCollection($userId: UUID!) {\n tagsCollection(\n filter: {user_id: {eq: $userId}}\n orderBy: {created_at: AscNullsLast}\n ) {\n edges {\n node {\n id\n name\n }\n }\n }\n}': types.TagsCollectionDocument, - 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_storage_object_id\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}': + 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}': types.TripDetailsDocument, 'query tripTagsCollection($filter: trip_tagsFilter) {\n trip_tagsCollection(filter: $filter) {\n edges {\n node {\n id\n trip_id\n tag_id\n }\n }\n }\n}': types.TripTagsCollectionDocument, - 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_storage_object_id\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}': + 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_url\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}': types.TripsCollectionDocument } @@ -65,14 +65,14 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: 'query activityCollection($id: UUID!) {\n activityCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n trip_id\n title\n time_from\n time_to\n address\n url\n memo\n cost\n image_storage_object_id\n }\n }\n }\n}' -): (typeof documents)['query activityCollection($id: UUID!) {\n activityCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n trip_id\n title\n time_from\n time_to\n address\n url\n memo\n cost\n image_storage_object_id\n }\n }\n }\n}'] + source: 'query activityCollection($id: UUID!) {\n activityCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n trip_id\n title\n time_from\n time_to\n address\n url\n memo\n cost\n cost_unit\n image_url\n }\n }\n }\n}' +): (typeof documents)['query activityCollection($id: UUID!) {\n activityCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n trip_id\n title\n time_from\n time_to\n address\n url\n memo\n cost\n cost_unit\n image_url\n }\n }\n }\n}'] /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: 'mutation createActivity($trip_id: UUID!, $title: String!, $time_from: Datetime, $time_to: Datetime, $address: String, $url: String, $memo: String, $cost: BigFloat, $cost_unit: String, $image_storage_object_id: UUID) {\n insertIntoactivityCollection(\n objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_storage_object_id: $image_storage_object_id}]\n ) {\n records {\n __typename\n id\n title\n }\n }\n}' -): (typeof documents)['mutation createActivity($trip_id: UUID!, $title: String!, $time_from: Datetime, $time_to: Datetime, $address: String, $url: String, $memo: String, $cost: BigFloat, $cost_unit: String, $image_storage_object_id: UUID) {\n insertIntoactivityCollection(\n objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_storage_object_id: $image_storage_object_id}]\n ) {\n records {\n __typename\n id\n title\n }\n }\n}'] + source: 'mutation createActivity($trip_id: UUID!, $title: String!, $time_from: Datetime, $time_to: Datetime, $address: String, $url: String, $memo: String, $cost: BigFloat, $cost_unit: String, $image_url: String) {\n insertIntoactivityCollection(\n objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_url: $image_url}]\n ) {\n records {\n __typename\n id\n title\n }\n }\n}' +): (typeof documents)['mutation createActivity($trip_id: UUID!, $title: String!, $time_from: Datetime, $time_to: Datetime, $address: String, $url: String, $memo: String, $cost: BigFloat, $cost_unit: String, $image_url: String) {\n insertIntoactivityCollection(\n objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_url: $image_url}]\n ) {\n records {\n __typename\n id\n title\n }\n }\n}'] /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -119,8 +119,8 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_storage_object_id\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}' -): (typeof documents)['query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_storage_object_id\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}'] + source: 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}' +): (typeof documents)['query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}'] /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -131,8 +131,8 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_storage_object_id\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}' -): (typeof documents)['query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_storage_object_id\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}'] + source: 'query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_url\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}' +): (typeof documents)['query tripsCollection($filter: tripsFilter, $orderBy: [tripsOrderBy!], $first: Int!, $after: Cursor) {\n tripsCollection(\n filter: $filter\n first: $first\n after: $after\n orderBy: $orderBy\n ) {\n edges {\n node {\n id\n id\n title\n date_from\n date_to\n image_url\n created_at\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n }\n }\n }\n }\n }\n pageInfo {\n startCursor\n endCursor\n hasPreviousPage\n hasNextPage\n }\n }\n}'] export function graphql(source: string) { return (documents as any)[source] ?? {} diff --git a/graphql-codegen/generated/graphql.ts b/graphql-codegen/generated/graphql.ts index 5e1d7a4..d42a57d 100644 --- a/graphql-codegen/generated/graphql.ts +++ b/graphql-codegen/generated/graphql.ts @@ -140,6 +140,8 @@ export type Mutation = { __typename?: 'Mutation' /** Deletes zero or more records from the `activity` collection */ deleteFromactivityCollection: ActivityDeleteResponse + /** Deletes zero or more records from the `activity_uploaded_files` collection */ + deleteFromactivity_uploaded_filesCollection: Activity_Uploaded_FilesDeleteResponse /** Deletes zero or more records from the `invitations` collection */ deleteFrominvitationsCollection: InvitationsDeleteResponse /** Deletes zero or more records from the `tags` collection */ @@ -152,6 +154,8 @@ export type Mutation = { deleteFromusersCollection: UsersDeleteResponse /** Adds one or more `activity` records to the collection */ insertIntoactivityCollection?: Maybe + /** Adds one or more `activity_uploaded_files` records to the collection */ + insertIntoactivity_uploaded_filesCollection?: Maybe /** Adds one or more `invitations` records to the collection */ insertIntoinvitationsCollection?: Maybe /** Adds one or more `tags` records to the collection */ @@ -164,6 +168,8 @@ export type Mutation = { insertIntousersCollection?: Maybe /** Updates zero or more records in the `activity` collection */ updateactivityCollection: ActivityUpdateResponse + /** Updates zero or more records in the `activity_uploaded_files` collection */ + updateactivity_uploaded_filesCollection: Activity_Uploaded_FilesUpdateResponse /** Updates zero or more records in the `invitations` collection */ updateinvitationsCollection: InvitationsUpdateResponse /** Updates zero or more records in the `tags` collection */ @@ -182,6 +188,12 @@ export type MutationDeleteFromactivityCollectionArgs = { filter?: InputMaybe } +/** The root type for creating and mutating data */ +export type MutationDeleteFromactivity_Uploaded_FilesCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe +} + /** The root type for creating and mutating data */ export type MutationDeleteFrominvitationsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -217,6 +229,11 @@ export type MutationInsertIntoactivityCollectionArgs = { objects: Array } +/** The root type for creating and mutating data */ +export type MutationInsertIntoactivity_Uploaded_FilesCollectionArgs = { + objects: Array +} + /** The root type for creating and mutating data */ export type MutationInsertIntoinvitationsCollectionArgs = { objects: Array @@ -249,6 +266,13 @@ export type MutationUpdateactivityCollectionArgs = { set: ActivityUpdateInput } +/** The root type for creating and mutating data */ +export type MutationUpdateactivity_Uploaded_FilesCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe + set: Activity_Uploaded_FilesUpdateInput +} + /** The root type for creating and mutating data */ export type MutationUpdateinvitationsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -320,6 +344,8 @@ export type Query = { __typename?: 'Query' /** A pagable collection of type `activity` */ activityCollection?: Maybe + /** A pagable collection of type `activity_uploaded_files` */ + activity_uploaded_filesCollection?: Maybe /** A pagable collection of type `invitations` */ invitationsCollection?: Maybe /** Retrieve a record by its `ID` */ @@ -344,6 +370,16 @@ export type QueryActivityCollectionArgs = { orderBy?: InputMaybe> } +/** The root type for querying data */ +export type QueryActivity_Uploaded_FilesCollectionArgs = { + after?: InputMaybe + before?: InputMaybe + filter?: InputMaybe + first?: InputMaybe + last?: InputMaybe + orderBy?: InputMaybe> +} + /** The root type for querying data */ export type QueryInvitationsCollectionArgs = { after?: InputMaybe @@ -438,11 +474,13 @@ export type UuidFilter = { export type Activity = Node & { __typename?: 'activity' + activity_uploaded_filesCollection?: Maybe address?: Maybe cost?: Maybe cost_unit?: Maybe + created_at: Scalars['Datetime']['output'] id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe memo?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -454,6 +492,15 @@ export type Activity = Node & { url?: Maybe } +export type ActivityActivity_Uploaded_FilesCollectionArgs = { + after?: InputMaybe + before?: InputMaybe + filter?: InputMaybe + first?: InputMaybe + last?: InputMaybe + orderBy?: InputMaybe> +} + export type ActivityConnection = { __typename?: 'activityConnection' edges: Array @@ -480,8 +527,9 @@ export type ActivityFilter = { and?: InputMaybe> cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe nodeId?: InputMaybe /** Negates a filter */ @@ -499,8 +547,9 @@ export type ActivityInsertInput = { address?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -521,8 +570,9 @@ export type ActivityOrderBy = { address?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -535,8 +585,9 @@ export type ActivityUpdateInput = { address?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe + created_at?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe memo?: InputMaybe time_from?: InputMaybe time_to?: InputMaybe @@ -553,6 +604,101 @@ export type ActivityUpdateResponse = { records: Array } +export type Activity_Uploaded_Files = Node & { + __typename?: 'activity_uploaded_files' + activity?: Maybe + activity_id?: Maybe + content_type: Scalars['String']['output'] + created_at: Scalars['Datetime']['output'] + file_data?: Maybe + file_name: Scalars['String']['output'] + file_url: Scalars['String']['output'] + id: Scalars['UUID']['output'] + /** Globally Unique Record Identifier */ + nodeId: Scalars['ID']['output'] +} + +export type Activity_Uploaded_FilesConnection = { + __typename?: 'activity_uploaded_filesConnection' + edges: Array + pageInfo: PageInfo +} + +export type Activity_Uploaded_FilesDeleteResponse = { + __typename?: 'activity_uploaded_filesDeleteResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Activity_Uploaded_FilesEdge = { + __typename?: 'activity_uploaded_filesEdge' + cursor: Scalars['String']['output'] + node: Activity_Uploaded_Files +} + +export type Activity_Uploaded_FilesFilter = { + activity_id?: InputMaybe + /** Returns true only if all its inner filters are true, otherwise returns false */ + and?: InputMaybe> + content_type?: InputMaybe + created_at?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe + nodeId?: InputMaybe + /** Negates a filter */ + not?: InputMaybe + /** Returns true if at least one of its inner filters is true, otherwise returns false */ + or?: InputMaybe> +} + +export type Activity_Uploaded_FilesInsertInput = { + activity_id?: InputMaybe + content_type?: InputMaybe + created_at?: InputMaybe + file_data?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe +} + +export type Activity_Uploaded_FilesInsertResponse = { + __typename?: 'activity_uploaded_filesInsertResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Activity_Uploaded_FilesOrderBy = { + activity_id?: InputMaybe + content_type?: InputMaybe + created_at?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe +} + +export type Activity_Uploaded_FilesUpdateInput = { + activity_id?: InputMaybe + content_type?: InputMaybe + created_at?: InputMaybe + file_data?: InputMaybe + file_name?: InputMaybe + file_url?: InputMaybe + id?: InputMaybe +} + +export type Activity_Uploaded_FilesUpdateResponse = { + __typename?: 'activity_uploaded_filesUpdateResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + export type Invitations = Node & { __typename?: 'invitations' email: Scalars['String']['output'] @@ -844,7 +990,7 @@ export type Trips = Node & { date_to?: Maybe description?: Maybe id: Scalars['UUID']['output'] - image_storage_object_id?: Maybe + image_url?: Maybe invitationsCollection?: Maybe /** Globally Unique Record Identifier */ nodeId: Scalars['ID']['output'] @@ -911,7 +1057,7 @@ export type TripsFilter = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe nodeId?: InputMaybe /** Negates a filter */ not?: InputMaybe @@ -929,7 +1075,7 @@ export type TripsInsertInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -950,7 +1096,7 @@ export type TripsOrderBy = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -963,7 +1109,7 @@ export type TripsUpdateInput = { date_to?: InputMaybe description?: InputMaybe id?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe title?: InputMaybe user_id?: InputMaybe } @@ -1129,7 +1275,8 @@ export type ActivityCollectionQuery = { url?: string | null memo?: string | null cost?: string | null - image_storage_object_id?: string | null + cost_unit?: string | null + image_url?: string | null } }> } | null @@ -1145,7 +1292,7 @@ export type CreateActivityMutationVariables = Exact<{ memo?: InputMaybe cost?: InputMaybe cost_unit?: InputMaybe - image_storage_object_id?: InputMaybe + image_url?: InputMaybe }> export type CreateActivityMutation = { @@ -1267,7 +1414,7 @@ export type TripDetailsQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null cost?: string | null cost_unit?: string | null invitationsCollection?: { @@ -1352,7 +1499,7 @@ export type TripsCollectionQuery = { title: string date_from: string date_to?: string | null - image_storage_object_id?: string | null + image_url?: string | null created_at: string invitationsCollection?: { __typename: 'invitationsConnection' @@ -1498,7 +1645,7 @@ export const GetUserDocument = { ] } as unknown as DocumentNode export const ActivityCollectionDocument = { - __meta__: { hash: '2d419044f6b09dcfdf15e868fceccda14add69f4' }, + __meta__: { hash: '5ba311a19d53ac42096cb55d1830aaf08f96fccf' }, kind: 'Document', definitions: [ { @@ -1612,10 +1759,11 @@ export const ActivityCollectionDocument = { }, { kind: 'Field', - name: { - kind: 'Name', - value: 'image_storage_object_id' - } + name: { kind: 'Name', value: 'cost_unit' } + }, + { + kind: 'Field', + name: { kind: 'Name', value: 'image_url' } } ] } @@ -1635,7 +1783,7 @@ export const ActivityCollectionDocument = { ActivityCollectionQueryVariables > export const CreateActivityDocument = { - __meta__: { hash: 'cefb2405ca17061bd5cfb056521d672580129e73' }, + __meta__: { hash: '22e6378e9a0ec7a9c28a6430981dcfebf7820216' }, kind: 'Document', definitions: [ { @@ -1716,9 +1864,9 @@ export const CreateActivityDocument = { kind: 'VariableDefinition', variable: { kind: 'Variable', - name: { kind: 'Name', value: 'image_storage_object_id' } + name: { kind: 'Name', value: 'image_url' } }, - type: { kind: 'NamedType', name: { kind: 'Name', value: 'UUID' } } + type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } } } ], selectionSet: { @@ -1812,16 +1960,10 @@ export const CreateActivityDocument = { }, { kind: 'ObjectField', - name: { - kind: 'Name', - value: 'image_storage_object_id' - }, + name: { kind: 'Name', value: 'image_url' }, value: { kind: 'Variable', - name: { - kind: 'Name', - value: 'image_storage_object_id' - } + name: { kind: 'Name', value: 'image_url' } } } ] @@ -2514,7 +2656,7 @@ export const TagsCollectionDocument = { ] } as unknown as DocumentNode export const TripDetailsDocument = { - __meta__: { hash: '12df849b2205e5cf49fd291f6cb8582aa49100c3' }, + __meta__: { hash: 'bbd255d8e0db3b7f99ea25021e5db3fcd72f4091' }, kind: 'Document', definitions: [ { @@ -2608,10 +2750,7 @@ export const TripDetailsDocument = { }, { kind: 'Field', - name: { - kind: 'Name', - value: 'image_storage_object_id' - } + name: { kind: 'Name', value: 'image_url' } }, { kind: 'Field', @@ -2973,7 +3112,7 @@ export const TripTagsCollectionDocument = { TripTagsCollectionQueryVariables > export const TripsCollectionDocument = { - __meta__: { hash: '70a61f873c23f1db13cef7cd265a9845e9bfc53e' }, + __meta__: { hash: '3256c7ff43134c13502c53f475e55fa91f55cabb' }, kind: 'Document', definitions: [ { @@ -3116,10 +3255,7 @@ export const TripsCollectionDocument = { }, { kind: 'Field', - name: { - kind: 'Name', - value: 'image_storage_object_id' - } + name: { kind: 'Name', value: 'image_url' } }, { kind: 'Field', diff --git a/graphql-codegen/generated/persisted-documents.json b/graphql-codegen/generated/persisted-documents.json index dac4db0..b75687e 100644 --- a/graphql-codegen/generated/persisted-documents.json +++ b/graphql-codegen/generated/persisted-documents.json @@ -1,7 +1,7 @@ { "00c528b2b1c851c06119aedb1fba6b5c885713cf": "query getUser($id: UUID!) { __typename usersCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename email id name profile_picture_url } } } }", - "2d419044f6b09dcfdf15e868fceccda14add69f4": "query activityCollection($id: UUID!) { __typename activityCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename address cost id image_storage_object_id memo time_from time_to title trip_id url } } } }", - "cefb2405ca17061bd5cfb056521d672580129e73": "mutation createActivity($address: String, $cost: BigFloat, $cost_unit: String, $image_storage_object_id: UUID, $memo: String, $time_from: Datetime, $time_to: Datetime, $title: String!, $trip_id: UUID!, $url: String) { __typename insertIntoactivityCollection( objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_storage_object_id: $image_storage_object_id}] ) { __typename records { __typename id title } } }", + "5ba311a19d53ac42096cb55d1830aaf08f96fccf": "query activityCollection($id: UUID!) { __typename activityCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename address cost cost_unit id image_url memo time_from time_to title trip_id url } } } }", + "22e6378e9a0ec7a9c28a6430981dcfebf7820216": "mutation createActivity($address: String, $cost: BigFloat, $cost_unit: String, $image_url: String, $memo: String, $time_from: Datetime, $time_to: Datetime, $title: String!, $trip_id: UUID!, $url: String) { __typename insertIntoactivityCollection( objects: [{trip_id: $trip_id, title: $title, time_from: $time_from, time_to: $time_to, address: $address, url: $url, memo: $memo, cost: $cost, cost_unit: $cost_unit, image_url: $image_url}] ) { __typename records { __typename id title } } }", "9ecd6081f83febe06337ebd01345eef596b81cf9": "mutation createTag($name: String!, $userId: UUID!) { __typename insertIntotagsCollection(objects: [{name: $name, user_id: $userId}]) { __typename records { __typename id name } } }", "68140ac8465fd7c6f5bab39db9eec02dab9501ef": "mutation createTrip($object: tripsInsertInput!) { __typename insertIntotripsCollection(objects: [$object]) { __typename records { __typename id title } } }", "b86b0c68b8ee2697ff1b539e5df92575cedb30f0": "mutation createTripTag($tagId: UUID!, $tripId: UUID!) { __typename insertIntotrip_tagsCollection(objects: [{trip_id: $tripId, tag_id: $tagId}]) { __typename records { __typename id tag_id trip_id } } }", @@ -9,7 +9,7 @@ "1a4d048db574dedfebd859dc737e16a42021f3ff": "mutation deleteTripTag($id: UUID!) { __typename deleteFromtrip_tagsCollection(filter: {id: {eq: $id}}) { __typename records { __typename id } } }", "7b9783d44e5c70098239e977664434de3eae6204": "mutation updateTrip($id: UUID!, $set: tripsUpdateInput!) { __typename updatetripsCollection(set: $set, filter: {id: {eq: $id}}) { __typename records { __typename id title } } }", "994a2e7e0694c279cbfeff6c8696cbbe6a0c687c": "query tagsCollection($userId: UUID!) { __typename tagsCollection( filter: {user_id: {eq: $userId}} orderBy: {created_at: AscNullsLast} ) { __typename edges { __typename node { __typename id name } } } }", - "12df849b2205e5cf49fd291f6cb8582aa49100c3": "query tripDetails($id: UUID!) { __typename tripsCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename address id time_from time_to title } } } cost cost_unit date_from date_to id image_storage_object_id invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title trip_tagsCollection { __typename edges { __typename node { __typename tags { __typename id name } } } } } } } }", + "bbd255d8e0db3b7f99ea25021e5db3fcd72f4091": "query tripDetails($id: UUID!) { __typename tripsCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename address id time_from time_to title } } } cost cost_unit date_from date_to id image_url invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title trip_tagsCollection { __typename edges { __typename node { __typename tags { __typename id name } } } } } } } }", "f4142b2a2f4ab96ce0e69488851fdff976486652": "query tripTagsCollection($filter: trip_tagsFilter) { __typename trip_tagsCollection(filter: $filter) { __typename edges { __typename node { __typename id tag_id trip_id } } } }", - "70a61f873c23f1db13cef7cd265a9845e9bfc53e": "query tripsCollection($after: Cursor, $filter: tripsFilter, $first: Int!, $orderBy: [tripsOrderBy!]) { __typename tripsCollection( filter: $filter first: $first after: $after orderBy: $orderBy ) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename id } } } created_at date_from date_to id id image_storage_object_id invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title } } pageInfo { __typename endCursor hasNextPage hasPreviousPage startCursor } } }" + "3256c7ff43134c13502c53f475e55fa91f55cabb": "query tripsCollection($after: Cursor, $filter: tripsFilter, $first: Int!, $orderBy: [tripsOrderBy!]) { __typename tripsCollection( filter: $filter first: $first after: $after orderBy: $orderBy ) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename id } } } created_at date_from date_to id id image_url invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title } } pageInfo { __typename endCursor hasNextPage hasPreviousPage startCursor } } }" } From f9b5b44b94f257592ba12a7f1668ab746c64ea90 Mon Sep 17 00:00:00 2001 From: samuraikun Date: Sat, 3 Feb 2024 17:48:08 -0800 Subject: [PATCH 09/15] Fix for eslint --- app/trip/[id]/action/update-image-metadata.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/trip/[id]/action/update-image-metadata.ts b/app/trip/[id]/action/update-image-metadata.ts index c54bcfb..924d636 100644 --- a/app/trip/[id]/action/update-image-metadata.ts +++ b/app/trip/[id]/action/update-image-metadata.ts @@ -34,12 +34,20 @@ export const updateImageMetadataAction = async ( .match({ id }) if (updateResponse.error) { - return { status: 'error', data: { publicUrl }, error: { message: updateResponse.error.message } } + return { + status: 'error', + data: { publicUrl }, + error: { message: updateResponse.error.message } + } } return { status: 'success', data: { publicUrl } } } catch (error) { console.error({ error }) - return { status: 'error', data: { publicUrl: '' }, error: { message: 'Failed to upload image' } } + return { + status: 'error', + data: { publicUrl: '' }, + error: { message: 'Failed to upload image' } + } } } From 21404891209bd07d8f195866af35e620cb8b8f20 Mon Sep 17 00:00:00 2001 From: samuraikun Date: Sat, 3 Feb 2024 17:54:19 -0800 Subject: [PATCH 10/15] Update image storage object ID to image URL in trip details --- app/trip/[id]/edit/page.tsx | 2 +- app/trip/hooks/useTripCreate.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/trip/[id]/edit/page.tsx b/app/trip/[id]/edit/page.tsx index e97d48f..3f97af1 100644 --- a/app/trip/[id]/edit/page.tsx +++ b/app/trip/[id]/edit/page.tsx @@ -103,7 +103,7 @@ export default function TripEditPage({ params }: { params: { id: string } }) { { title: data.title, date_from: formatToISODate(data.date_from), date_to: data.date_to ? formatToISODate(data.date_to) : null, - image_storage_object_id: data.image_storage_object_id, + image_url: data.image_url, cost: data.cost, cost_unit: data.cost_unit, user_id: userId From 1f6c4da135c36805e1fec52d314cf9ee2762416c Mon Sep 17 00:00:00 2001 From: Kana Taguchi Date: Tue, 6 Feb 2024 12:40:22 -0800 Subject: [PATCH 11/15] Add trip delete and fix trip_tag delete --- app/components/modal/confirm-modal.tsx | 23 +- .../modal/stories/confirm-model.stories.tsx | 8 +- .../[id]/components/trip-details-header.tsx | 31 +- app/trip/[id]/page.tsx | 43 ++- app/trip/components/tag-form-modal.tsx | 171 ++++++----- app/trip/components/trip-form.tsx | 1 + app/trip/graphql/mutation/deleteTrip.graphql | 11 + app/trip/graphql/query/tripDetails.graphql | 2 +- app/trip/hooks/index.ts | 2 + app/trip/hooks/use-trip-delete.ts | 53 ++++ app/trip/hooks/use-trip-details-get.ts | 21 ++ app/trip/hooks/useTagCreateDelete.ts | 17 +- graphql-codegen/generated/api.ts | 220 +++++++++++--- graphql-codegen/generated/gql.ts | 14 +- graphql-codegen/generated/graphql.ts | 271 ++++++++++++++---- .../generated/persisted-documents.json | 3 +- 16 files changed, 682 insertions(+), 209 deletions(-) create mode 100644 app/trip/graphql/mutation/deleteTrip.graphql create mode 100644 app/trip/hooks/use-trip-delete.ts create mode 100644 app/trip/hooks/use-trip-details-get.ts diff --git a/app/components/modal/confirm-modal.tsx b/app/components/modal/confirm-modal.tsx index 6b7f765..8662454 100644 --- a/app/components/modal/confirm-modal.tsx +++ b/app/components/modal/confirm-modal.tsx @@ -4,42 +4,41 @@ import { ModalContent, ModalFooter, ModalBody, - ModalCloseButton, - Text + ModalCloseButton } from '@chakra-ui/react' import { SecondaryButton, AlertButton } from '../button' type ConfirmModalProps = { isOpen: boolean onClose: () => void - confirmText: string + confirmBody: React.ReactNode submitLabel: string onClick: () => void + isMutating?: boolean } export const ConfirmModal = ({ isOpen, onClose, - confirmText, + confirmBody, submitLabel, - onClick + onClick, + isMutating }: ConfirmModalProps) => { return ( - - - Are you sure you want to {confirmText}? - - + {confirmBody} - + Close - {submitLabel} + + {submitLabel} + diff --git a/app/components/modal/stories/confirm-model.stories.tsx b/app/components/modal/stories/confirm-model.stories.tsx index e0992e7..efeeba2 100644 --- a/app/components/modal/stories/confirm-model.stories.tsx +++ b/app/components/modal/stories/confirm-model.stories.tsx @@ -1,4 +1,4 @@ -import { useDisclosure } from '@chakra-ui/react' +import { useDisclosure, Text } from '@chakra-ui/react' import { ConfirmModal } from '@/components/modal' import type { Meta, StoryObj } from '@storybook/react' @@ -11,7 +11,11 @@ const WrapperComponent = () => { + Are you sure you want to delete this tag? + + } onClick={() => {}} submitLabel="Delete" /> diff --git a/app/trip/[id]/components/trip-details-header.tsx b/app/trip/[id]/components/trip-details-header.tsx index d7fc10b..ecff77f 100644 --- a/app/trip/[id]/components/trip-details-header.tsx +++ b/app/trip/[id]/components/trip-details-header.tsx @@ -6,13 +6,17 @@ import { useColorModeValue, Image as ChakraImage, Link, - IconButton + IconButton, + useDisclosure, + Text } from '@chakra-ui/react' import Image from 'next/image' import { useRouter } from 'next/navigation' import { FiEdit3, FiShare2, FiTrash2 } from 'react-icons/fi' import { MdManageAccounts, MdAccountCircle } from 'react-icons/md' +import { ConfirmModal } from '@/components/modal' import { formatDateToSlash } from '@/libs/utils' +import { useTripDelete } from '../../hooks' type TripDetailsHeaderProps = { id: string @@ -50,6 +54,14 @@ export const TripDetailsHeader = ({ const color = useColorModeValue('black', 'gray.300') const tagBgColor = useColorModeValue('primary.700', 'primary.800') + const { + isOpen: isDeleteModalOpen, + onOpen: onDeleteModalOpen, + onClose: onDeleteModalClose + } = useDisclosure() + + const { deleteTrip, isTripDeleting } = useTripDelete(id) + return ( - {/* TODO Change to modal */} {}} + onClick={onDeleteModalOpen} variant="roundIcon" p={{ base: '6px', md: '10px' }} > @@ -205,6 +216,20 @@ export const TripDetailsHeader = ({ )} + + {/* Delete Trip Modal */} + + Are you sure you want to delete this trip? + + } + onClick={deleteTrip} + isMutating={isTripDeleting} + submitLabel="Delete" + /> ) } diff --git a/app/trip/[id]/page.tsx b/app/trip/[id]/page.tsx index b3a24d7..9bc0edb 100644 --- a/app/trip/[id]/page.tsx +++ b/app/trip/[id]/page.tsx @@ -6,9 +6,9 @@ import { createClient } from '@supabase/supabase-js' import { useRouter } from 'next/navigation' import { PrimaryButton } from '@/components/button' import { Loading } from '@/components/loading' +import { useTripDetailsGet } from '../hooks' import { updateImageMetadataAction } from './action/update-image-metadata' import { TripDetailsHeader, TripDetailsTabs } from './components' -import { useTripDetailsQuery } from '@generated/api' export default function TripDetailsPage({ params @@ -19,20 +19,13 @@ export default function TripDetailsPage({ const color = useColorModeValue('black', 'gray.300') const router = useRouter() + const { tripDetailsData, tripDetailsLoading, tripDetailsRefetch } = + useTripDetailsGet(params.id) - const { - data: tripData, - loading: tripLoading, - refetch: refetchTrip - } = useTripDetailsQuery({ - variables: { - id: params.id - } - }) - - if (!tripData && !tripLoading) throw new Error('No trip data found') + if (!tripDetailsData && !tripDetailsLoading) + throw new Error('No trip data found') - const tripDataCollection = tripData?.tripsCollection + const tripData = tripDetailsData?.tripsCollection const [selectedImage, setSelectedImage] = useState(null) const uploadImage = async (id: string, file: File) => { @@ -53,7 +46,7 @@ export default function TripDetailsPage({ await updateImageMetadataAction(id, uploadData.path) setSelectedImage(file) - await refetchTrip() + await tripDetailsRefetch() } catch (error) { console.error({ error }) throw error @@ -67,24 +60,24 @@ export default function TripDetailsPage({ pt={{ base: '0px', md: '30px' }} pb={{ base: '40px', md: '80px' }} > - {!tripDataCollection || tripLoading ? ( + {!tripData || tripDetailsLoading ? ( ) : ( <> ({ id: invitation.node.users?.id, image: invitation.node.users?.profile_picture_url @@ -92,7 +85,7 @@ export default function TripDetailsPage({ ) || [] } tags={ - tripDataCollection.edges[0].node.trip_tagsCollection?.edges.map( + tripData.edges[0].node.trip_tagsCollection?.edges.map( (tag) => ({ id: tag.node.tags?.id, name: tag.node.tags?.name @@ -103,7 +96,7 @@ export default function TripDetailsPage({ ({ id: activity.node.id, timeFrom: activity.node.time_from, diff --git a/app/trip/components/tag-form-modal.tsx b/app/trip/components/tag-form-modal.tsx index ef4f307..e7b06d4 100644 --- a/app/trip/components/tag-form-modal.tsx +++ b/app/trip/components/tag-form-modal.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react' import { Modal, ModalOverlay, @@ -11,15 +12,19 @@ import { Tag, useColorModeValue, Box, - Heading + Heading, + useDisclosure, + Text } from '@chakra-ui/react' import { FiPlusCircle, FiX } from 'react-icons/fi' import { InputIconButton } from '@/components/input' import { Loading } from '@/components/loading' +import { ConfirmModal } from '@/components/modal' import { useTagCreateDelete } from '../hooks' type TagFormModalProps = { isOpen: boolean + onOpen: () => void onClose: () => void allTags: { id: string; name: string }[] tagsCollectionRefetch: () => void @@ -27,12 +32,20 @@ type TagFormModalProps = { export const TagFormModal = ({ isOpen, + onOpen, onClose, allTags, tagsCollectionRefetch }: TagFormModalProps) => { + const [tagToDelete, setTagToDelete] = useState('') const tagBgColor = useColorModeValue('primary.700', 'primary.800') + const { + isOpen: isDeleteModalOpen, + onOpen: onDeleteModalOpen, + onClose: onDeleteModalClose + } = useDisclosure() + const { addEnterHandler, addTag, @@ -44,73 +57,97 @@ export const TagFormModal = ({ } = useTagCreateDelete(tagsCollectionRefetch) return ( - - - - - - - - - Tag List - - - {isCreating || isDeleting ? ( - - ) : ( - <> - {allTags.map((tag) => ( - - {tag.name} - deleteTag(tag.id)} + <> + + + + + + + + + Tag List + + + {isCreating || isDeleting ? ( + + ) : ( + <> + {allTags.map((tag) => ( + - - - - ))} - - )} - - - - - Add New Tag - - - - addEnterHandler(e)} - onClick={addTag} - {...register('name')} - /> - {errors?.name?.message} - + {tag.name} + { + setTagToDelete(tag.id) + onClose() + onDeleteModalOpen() + }} + > + + + + ))} + + )} + - - - - - - + + + Add New Tag + + + + addEnterHandler(e)} + onClick={addTag} + {...register('name')} + /> + {errors?.name?.message} + + + + + + + + + + { + onDeleteModalClose() + onOpen() + }} + onClick={() => deleteTag(tagToDelete)} + submitLabel="Delete" + confirmBody={ + <> + + Are you sure you want to delete this tag? + + *This tag in other trips will also be deleted. + + } + /> + ) } diff --git a/app/trip/components/trip-form.tsx b/app/trip/components/trip-form.tsx index a2f406a..09be2ee 100644 --- a/app/trip/components/trip-form.tsx +++ b/app/trip/components/trip-form.tsx @@ -225,6 +225,7 @@ export const TripForm = ({ tripDetails, tags, tripTags }: TripFormProps) => { { + const toast = useToast() + const router = useRouter() + const userId = useUserId() + const [deleteTripMutation, { loading: isTripDeleting }] = + useDeleteTripMutation() + + const { tripsRefetch } = useTripsGet() + + const deleteTrip = async () => { + try { + await deleteTripMutation({ + variables: { + id, + userId + } + }) + + tripsRefetch() + router.push('/') + + toast({ + title: 'Successfully deleted!', + status: 'success', + duration: 2000, + isClosable: true, + position: 'top' + }) + } catch (error) { + console.error(error) + toast({ + title: "We're sorry, but you failed to delete a trip", + description: + error instanceof Error ? error.message : 'Please try again later.', + status: 'error', + duration: 5000, + isClosable: true, + position: 'top' + }) + } + } + + return { + deleteTrip, + isTripDeleting + } +} diff --git a/app/trip/hooks/use-trip-details-get.ts b/app/trip/hooks/use-trip-details-get.ts new file mode 100644 index 0000000..219819f --- /dev/null +++ b/app/trip/hooks/use-trip-details-get.ts @@ -0,0 +1,21 @@ +import { useTripDetailsQuery } from '@generated/api' + +export const useTripDetailsGet = (id?: string) => { + const { + data: tripDetailsData, + loading: tripDetailsLoading, + refetch: tripDetailsRefetch, + client: tripDetailsClient + } = useTripDetailsQuery({ + variables: { + id + } + }) + + return { + tripDetailsData, + tripDetailsLoading, + tripDetailsRefetch, + tripDetailsClient + } +} diff --git a/app/trip/hooks/useTagCreateDelete.ts b/app/trip/hooks/useTagCreateDelete.ts index 18b38e1..e93dc3f 100644 --- a/app/trip/hooks/useTagCreateDelete.ts +++ b/app/trip/hooks/useTagCreateDelete.ts @@ -3,6 +3,7 @@ import { useForm } from 'react-hook-form' import { useToast } from '@chakra-ui/react' import { useUserId } from '@/providers/session-provider' import { TagSchema, tagSchemaResolver } from '../schema' +import { useTripsGet, useTripDetailsGet } from '.' import { useCreateTagMutation, useDeleteTagMutation } from '@generated/api' export const useTagCreateDelete = (tagsCollectionRefetch: () => void) => { @@ -21,6 +22,9 @@ export const useTagCreateDelete = (tagsCollectionRefetch: () => void) => { const [createTagMutation, { loading: isCreating }] = useCreateTagMutation() const [deleteTagMutation, { loading: isDeleting }] = useDeleteTagMutation() + const { tripsRefetch } = useTripsGet() + const { tripDetailsClient } = useTripDetailsGet() + const addTag = async (input: TagSchema) => { try { await createTagMutation({ @@ -32,6 +36,7 @@ export const useTagCreateDelete = (tagsCollectionRefetch: () => void) => { reset() tagsCollectionRefetch() + tripsRefetch() } catch (error) { console.error(error) toast({ @@ -58,10 +63,20 @@ export const useTagCreateDelete = (tagsCollectionRefetch: () => void) => { await deleteTagMutation({ variables: { id: id - } + }, + refetchQueries: [] }) + // refetch all tripDetails in case tag is used + tripDetailsClient.resetStore() tagsCollectionRefetch() + toast({ + title: 'Successfully deleted!', + status: 'success', + duration: 2000, + isClosable: true, + position: 'top' + }) } catch (error) { console.error(error) toast({ diff --git a/graphql-codegen/generated/api.ts b/graphql-codegen/generated/api.ts index 2a80927..8fb224a 100644 --- a/graphql-codegen/generated/api.ts +++ b/graphql-codegen/generated/api.ts @@ -138,6 +138,8 @@ export type Mutation = { deleteFrominvitationsCollection: InvitationsDeleteResponse /** Deletes zero or more records from the `tags` collection */ deleteFromtagsCollection: TagsDeleteResponse + /** Deletes zero or more records from the `test_tenant` collection */ + deleteFromtest_tenantCollection: Test_TenantDeleteResponse /** Deletes zero or more records from the `trip_tags` collection */ deleteFromtrip_tagsCollection: Trip_TagsDeleteResponse /** Deletes zero or more records from the `trips` collection */ @@ -152,6 +154,8 @@ export type Mutation = { insertIntoinvitationsCollection?: Maybe /** Adds one or more `tags` records to the collection */ insertIntotagsCollection?: Maybe + /** Adds one or more `test_tenant` records to the collection */ + insertIntotest_tenantCollection?: Maybe /** Adds one or more `trip_tags` records to the collection */ insertIntotrip_tagsCollection?: Maybe /** Adds one or more `trips` records to the collection */ @@ -166,6 +170,8 @@ export type Mutation = { updateinvitationsCollection: InvitationsUpdateResponse /** Updates zero or more records in the `tags` collection */ updatetagsCollection: TagsUpdateResponse + /** Updates zero or more records in the `test_tenant` collection */ + updatetest_tenantCollection: Test_TenantUpdateResponse /** Updates zero or more records in the `trip_tags` collection */ updatetrip_tagsCollection: Trip_TagsUpdateResponse /** Updates zero or more records in the `trips` collection */ @@ -198,6 +204,12 @@ export type MutationDeleteFromtagsCollectionArgs = { filter?: InputMaybe } +/** The root type for creating and mutating data */ +export type MutationDeleteFromtest_TenantCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe +} + /** The root type for creating and mutating data */ export type MutationDeleteFromtrip_TagsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -236,6 +248,11 @@ export type MutationInsertIntotagsCollectionArgs = { objects: Array } +/** The root type for creating and mutating data */ +export type MutationInsertIntotest_TenantCollectionArgs = { + objects: Array +} + /** The root type for creating and mutating data */ export type MutationInsertIntotrip_TagsCollectionArgs = { objects: Array @@ -279,6 +296,13 @@ export type MutationUpdatetagsCollectionArgs = { set: TagsUpdateInput } +/** The root type for creating and mutating data */ +export type MutationUpdatetest_TenantCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe + set: Test_TenantUpdateInput +} + /** The root type for creating and mutating data */ export type MutationUpdatetrip_TagsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -344,6 +368,8 @@ export type Query = { node?: Maybe /** A pagable collection of type `tags` */ tagsCollection?: Maybe + /** A pagable collection of type `test_tenant` */ + test_tenantCollection?: Maybe /** A pagable collection of type `trip_tags` */ trip_tagsCollection?: Maybe /** A pagable collection of type `trips` */ @@ -397,6 +423,16 @@ export type QueryTagsCollectionArgs = { orderBy?: InputMaybe> } +/** The root type for querying data */ +export type QueryTest_TenantCollectionArgs = { + after?: InputMaybe + before?: InputMaybe + filter?: InputMaybe + first?: InputMaybe + last?: InputMaybe + orderBy?: InputMaybe> +} + /** The root type for querying data */ export type QueryTrip_TagsCollectionArgs = { after?: InputMaybe @@ -515,8 +551,6 @@ export type ActivityEdge = { export type ActivityFilter = { address?: InputMaybe - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> cost?: InputMaybe cost_unit?: InputMaybe created_at?: InputMaybe @@ -524,10 +558,6 @@ export type ActivityFilter = { image_url?: InputMaybe memo?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> time_from?: InputMaybe time_to?: InputMaybe title?: InputMaybe @@ -632,18 +662,12 @@ export type Activity_Uploaded_FilesEdge = { export type Activity_Uploaded_FilesFilter = { activity_id?: InputMaybe - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> content_type?: InputMaybe created_at?: InputMaybe file_name?: InputMaybe file_url?: InputMaybe id?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> } export type Activity_Uploaded_FilesInsertInput = { @@ -727,18 +751,12 @@ export type InvitationsEdge = { } export type InvitationsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> email?: InputMaybe id?: InputMaybe invitation_url?: InputMaybe invited_by_user_id?: InputMaybe invitee_user_id?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> permission_level?: InputMaybe trip_id?: InputMaybe } @@ -844,16 +862,10 @@ export type TagsEdge = { } export type TagsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> created_at?: InputMaybe id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> user_id?: InputMaybe } @@ -894,6 +906,69 @@ export type TagsUpdateResponse = { records: Array } +export type Test_Tenant = Node & { + __typename?: 'test_tenant' + details?: Maybe + id: Scalars['Int']['output'] + /** Globally Unique Record Identifier */ + nodeId: Scalars['ID']['output'] +} + +export type Test_TenantConnection = { + __typename?: 'test_tenantConnection' + edges: Array + pageInfo: PageInfo +} + +export type Test_TenantDeleteResponse = { + __typename?: 'test_tenantDeleteResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Test_TenantEdge = { + __typename?: 'test_tenantEdge' + cursor: Scalars['String']['output'] + node: Test_Tenant +} + +export type Test_TenantFilter = { + details?: InputMaybe + id?: InputMaybe + nodeId?: InputMaybe +} + +export type Test_TenantInsertInput = { + details?: InputMaybe +} + +export type Test_TenantInsertResponse = { + __typename?: 'test_tenantInsertResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Test_TenantOrderBy = { + details?: InputMaybe + id?: InputMaybe +} + +export type Test_TenantUpdateInput = { + details?: InputMaybe +} + +export type Test_TenantUpdateResponse = { + __typename?: 'test_tenantUpdateResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + export type Trip_Tags = Node & { __typename?: 'trip_tags' id: Scalars['UUID']['output'] @@ -926,14 +1001,8 @@ export type Trip_TagsEdge = { } export type Trip_TagsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> id?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> tag_id?: InputMaybe trip_id?: InputMaybe } @@ -1040,8 +1109,6 @@ export type TripsEdge = { } export type TripsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> cost?: InputMaybe cost_unit?: InputMaybe created_at?: InputMaybe @@ -1051,10 +1118,6 @@ export type TripsFilter = { id?: InputMaybe image_url?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> title?: InputMaybe user_id?: InputMaybe } @@ -1175,16 +1238,10 @@ export type UsersEdge = { } export type UsersFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> email?: InputMaybe id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> profile_picture_url?: InputMaybe } @@ -1350,6 +1407,19 @@ export type DeleteTagMutation = { } } +export type DeleteTripMutationVariables = Exact<{ + id: Scalars['UUID']['input'] + userId: Scalars['UUID']['input'] +}> + +export type DeleteTripMutation = { + __typename: 'Mutation' + deleteFromtripsCollection: { + __typename: 'tripsDeleteResponse' + records: Array<{ __typename: 'trips'; id: string; title: string }> + } +} + export type DeleteTripTagMutationVariables = Exact<{ id: Scalars['UUID']['input'] }> @@ -1391,7 +1461,7 @@ export type TagsCollectionQuery = { } export type TripDetailsQueryVariables = Exact<{ - id: Scalars['UUID']['input'] + id?: InputMaybe }> export type TripDetailsQuery = { @@ -2016,6 +2086,64 @@ export type DeleteTagMutationOptions = Apollo.BaseMutationOptions< DeleteTagMutation, DeleteTagMutationVariables > +export const DeleteTripDocument = gql` + mutation deleteTrip($id: UUID!, $userId: UUID!) { + __typename + deleteFromtripsCollection( + filter: { id: { eq: $id }, user_id: { eq: $userId } } + ) { + __typename + records { + __typename + id + title + } + } + } +` +export type DeleteTripMutationFn = Apollo.MutationFunction< + DeleteTripMutation, + DeleteTripMutationVariables +> + +/** + * __useDeleteTripMutation__ + * + * To run a mutation, you first call `useDeleteTripMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteTripMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [deleteTripMutation, { data, loading, error }] = useDeleteTripMutation({ + * variables: { + * id: // value for 'id' + * userId: // value for 'userId' + * }, + * }); + */ +export function useDeleteTripMutation( + baseOptions?: Apollo.MutationHookOptions< + DeleteTripMutation, + DeleteTripMutationVariables + > +) { + const options = { ...defaultOptions, ...baseOptions } + return Apollo.useMutation( + DeleteTripDocument, + options + ) +} +export type DeleteTripMutationHookResult = ReturnType< + typeof useDeleteTripMutation +> +export type DeleteTripMutationResult = Apollo.MutationResult +export type DeleteTripMutationOptions = Apollo.BaseMutationOptions< + DeleteTripMutation, + DeleteTripMutationVariables +> export const DeleteTripTagDocument = gql` mutation deleteTripTag($id: UUID!) { __typename @@ -2218,7 +2346,7 @@ export function refetchTagsCollectionQuery( return { query: TagsCollectionDocument, variables: variables } } export const TripDetailsDocument = gql` - query tripDetails($id: UUID!) { + query tripDetails($id: UUID) { __typename tripsCollection(filter: { id: { eq: $id } }) { __typename @@ -2298,7 +2426,7 @@ export const TripDetailsDocument = gql` * }); */ export function useTripDetailsQuery( - baseOptions: Apollo.QueryHookOptions< + baseOptions?: Apollo.QueryHookOptions< TripDetailsQuery, TripDetailsQueryVariables > @@ -2344,7 +2472,7 @@ export type TripDetailsQueryResult = Apollo.QueryResult< TripDetailsQuery, TripDetailsQueryVariables > -export function refetchTripDetailsQuery(variables: TripDetailsQueryVariables) { +export function refetchTripDetailsQuery(variables?: TripDetailsQueryVariables) { return { query: TripDetailsDocument, variables: variables } } export const TripTagsCollectionDocument = gql` diff --git a/graphql-codegen/generated/gql.ts b/graphql-codegen/generated/gql.ts index 5c1959e..5136b13 100644 --- a/graphql-codegen/generated/gql.ts +++ b/graphql-codegen/generated/gql.ts @@ -27,13 +27,15 @@ const documents = { types.CreateTripTagDocument, 'mutation deleteTag($id: UUID!) {\n deleteFromtagsCollection(filter: {id: {eq: $id}}) {\n records {\n __typename\n id\n name\n }\n }\n}': types.DeleteTagDocument, + 'mutation deleteTrip($id: UUID!, $userId: UUID!) {\n deleteFromtripsCollection(filter: {id: {eq: $id}, user_id: {eq: $userId}}) {\n records {\n __typename\n id\n title\n }\n }\n}': + types.DeleteTripDocument, 'mutation deleteTripTag($id: UUID!) {\n deleteFromtrip_tagsCollection(filter: {id: {eq: $id}}) {\n records {\n __typename\n id\n }\n }\n}': types.DeleteTripTagDocument, 'mutation updateTrip($id: UUID!, $set: tripsUpdateInput!) {\n updatetripsCollection(set: $set, filter: {id: {eq: $id}}) {\n records {\n id\n title\n }\n }\n}': types.UpdateTripDocument, 'query tagsCollection($userId: UUID!) {\n tagsCollection(\n filter: {user_id: {eq: $userId}}\n orderBy: {created_at: AscNullsLast}\n ) {\n edges {\n node {\n id\n name\n }\n }\n }\n}': types.TagsCollectionDocument, - 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}': + 'query tripDetails($id: UUID) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}': types.TripDetailsDocument, 'query tripTagsCollection($filter: trip_tagsFilter) {\n trip_tagsCollection(filter: $filter) {\n edges {\n node {\n id\n trip_id\n tag_id\n }\n }\n }\n}': types.TripTagsCollectionDocument, @@ -97,6 +99,12 @@ export function graphql( export function graphql( source: 'mutation deleteTag($id: UUID!) {\n deleteFromtagsCollection(filter: {id: {eq: $id}}) {\n records {\n __typename\n id\n name\n }\n }\n}' ): (typeof documents)['mutation deleteTag($id: UUID!) {\n deleteFromtagsCollection(filter: {id: {eq: $id}}) {\n records {\n __typename\n id\n name\n }\n }\n}'] +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql( + source: 'mutation deleteTrip($id: UUID!, $userId: UUID!) {\n deleteFromtripsCollection(filter: {id: {eq: $id}, user_id: {eq: $userId}}) {\n records {\n __typename\n id\n title\n }\n }\n}' +): (typeof documents)['mutation deleteTrip($id: UUID!, $userId: UUID!) {\n deleteFromtripsCollection(filter: {id: {eq: $id}, user_id: {eq: $userId}}) {\n records {\n __typename\n id\n title\n }\n }\n}'] /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -119,8 +127,8 @@ export function graphql( * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: 'query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}' -): (typeof documents)['query tripDetails($id: UUID!) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}'] + source: 'query tripDetails($id: UUID) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}' +): (typeof documents)['query tripDetails($id: UUID) {\n tripsCollection(filter: {id: {eq: $id}}) {\n edges {\n node {\n id\n title\n date_from\n date_to\n image_url\n cost\n cost_unit\n invitationsCollection {\n edges {\n node {\n users {\n id\n profile_picture_url\n }\n }\n }\n }\n activityCollection {\n edges {\n node {\n id\n title\n time_from\n time_to\n address\n }\n }\n }\n trip_tagsCollection {\n edges {\n node {\n tags {\n id\n name\n }\n }\n }\n }\n }\n }\n }\n}'] /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/graphql-codegen/generated/graphql.ts b/graphql-codegen/generated/graphql.ts index d42a57d..1f9ad04 100644 --- a/graphql-codegen/generated/graphql.ts +++ b/graphql-codegen/generated/graphql.ts @@ -146,6 +146,8 @@ export type Mutation = { deleteFrominvitationsCollection: InvitationsDeleteResponse /** Deletes zero or more records from the `tags` collection */ deleteFromtagsCollection: TagsDeleteResponse + /** Deletes zero or more records from the `test_tenant` collection */ + deleteFromtest_tenantCollection: Test_TenantDeleteResponse /** Deletes zero or more records from the `trip_tags` collection */ deleteFromtrip_tagsCollection: Trip_TagsDeleteResponse /** Deletes zero or more records from the `trips` collection */ @@ -160,6 +162,8 @@ export type Mutation = { insertIntoinvitationsCollection?: Maybe /** Adds one or more `tags` records to the collection */ insertIntotagsCollection?: Maybe + /** Adds one or more `test_tenant` records to the collection */ + insertIntotest_tenantCollection?: Maybe /** Adds one or more `trip_tags` records to the collection */ insertIntotrip_tagsCollection?: Maybe /** Adds one or more `trips` records to the collection */ @@ -174,6 +178,8 @@ export type Mutation = { updateinvitationsCollection: InvitationsUpdateResponse /** Updates zero or more records in the `tags` collection */ updatetagsCollection: TagsUpdateResponse + /** Updates zero or more records in the `test_tenant` collection */ + updatetest_tenantCollection: Test_TenantUpdateResponse /** Updates zero or more records in the `trip_tags` collection */ updatetrip_tagsCollection: Trip_TagsUpdateResponse /** Updates zero or more records in the `trips` collection */ @@ -206,6 +212,12 @@ export type MutationDeleteFromtagsCollectionArgs = { filter?: InputMaybe } +/** The root type for creating and mutating data */ +export type MutationDeleteFromtest_TenantCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe +} + /** The root type for creating and mutating data */ export type MutationDeleteFromtrip_TagsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -244,6 +256,11 @@ export type MutationInsertIntotagsCollectionArgs = { objects: Array } +/** The root type for creating and mutating data */ +export type MutationInsertIntotest_TenantCollectionArgs = { + objects: Array +} + /** The root type for creating and mutating data */ export type MutationInsertIntotrip_TagsCollectionArgs = { objects: Array @@ -287,6 +304,13 @@ export type MutationUpdatetagsCollectionArgs = { set: TagsUpdateInput } +/** The root type for creating and mutating data */ +export type MutationUpdatetest_TenantCollectionArgs = { + atMost?: Scalars['Int']['input'] + filter?: InputMaybe + set: Test_TenantUpdateInput +} + /** The root type for creating and mutating data */ export type MutationUpdatetrip_TagsCollectionArgs = { atMost?: Scalars['Int']['input'] @@ -352,6 +376,8 @@ export type Query = { node?: Maybe /** A pagable collection of type `tags` */ tagsCollection?: Maybe + /** A pagable collection of type `test_tenant` */ + test_tenantCollection?: Maybe /** A pagable collection of type `trip_tags` */ trip_tagsCollection?: Maybe /** A pagable collection of type `trips` */ @@ -405,6 +431,16 @@ export type QueryTagsCollectionArgs = { orderBy?: InputMaybe> } +/** The root type for querying data */ +export type QueryTest_TenantCollectionArgs = { + after?: InputMaybe + before?: InputMaybe + filter?: InputMaybe + first?: InputMaybe + last?: InputMaybe + orderBy?: InputMaybe> +} + /** The root type for querying data */ export type QueryTrip_TagsCollectionArgs = { after?: InputMaybe @@ -523,8 +559,6 @@ export type ActivityEdge = { export type ActivityFilter = { address?: InputMaybe - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> cost?: InputMaybe cost_unit?: InputMaybe created_at?: InputMaybe @@ -532,10 +566,6 @@ export type ActivityFilter = { image_url?: InputMaybe memo?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> time_from?: InputMaybe time_to?: InputMaybe title?: InputMaybe @@ -640,18 +670,12 @@ export type Activity_Uploaded_FilesEdge = { export type Activity_Uploaded_FilesFilter = { activity_id?: InputMaybe - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> content_type?: InputMaybe created_at?: InputMaybe file_name?: InputMaybe file_url?: InputMaybe id?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> } export type Activity_Uploaded_FilesInsertInput = { @@ -735,18 +759,12 @@ export type InvitationsEdge = { } export type InvitationsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> email?: InputMaybe id?: InputMaybe invitation_url?: InputMaybe invited_by_user_id?: InputMaybe invitee_user_id?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> permission_level?: InputMaybe trip_id?: InputMaybe } @@ -852,16 +870,10 @@ export type TagsEdge = { } export type TagsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> created_at?: InputMaybe id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> user_id?: InputMaybe } @@ -902,6 +914,69 @@ export type TagsUpdateResponse = { records: Array } +export type Test_Tenant = Node & { + __typename?: 'test_tenant' + details?: Maybe + id: Scalars['Int']['output'] + /** Globally Unique Record Identifier */ + nodeId: Scalars['ID']['output'] +} + +export type Test_TenantConnection = { + __typename?: 'test_tenantConnection' + edges: Array + pageInfo: PageInfo +} + +export type Test_TenantDeleteResponse = { + __typename?: 'test_tenantDeleteResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Test_TenantEdge = { + __typename?: 'test_tenantEdge' + cursor: Scalars['String']['output'] + node: Test_Tenant +} + +export type Test_TenantFilter = { + details?: InputMaybe + id?: InputMaybe + nodeId?: InputMaybe +} + +export type Test_TenantInsertInput = { + details?: InputMaybe +} + +export type Test_TenantInsertResponse = { + __typename?: 'test_tenantInsertResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + +export type Test_TenantOrderBy = { + details?: InputMaybe + id?: InputMaybe +} + +export type Test_TenantUpdateInput = { + details?: InputMaybe +} + +export type Test_TenantUpdateResponse = { + __typename?: 'test_tenantUpdateResponse' + /** Count of the records impacted by the mutation */ + affectedCount: Scalars['Int']['output'] + /** Array of records impacted by the mutation */ + records: Array +} + export type Trip_Tags = Node & { __typename?: 'trip_tags' id: Scalars['UUID']['output'] @@ -934,14 +1009,8 @@ export type Trip_TagsEdge = { } export type Trip_TagsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> id?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> tag_id?: InputMaybe trip_id?: InputMaybe } @@ -1048,8 +1117,6 @@ export type TripsEdge = { } export type TripsFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> cost?: InputMaybe cost_unit?: InputMaybe created_at?: InputMaybe @@ -1059,10 +1126,6 @@ export type TripsFilter = { id?: InputMaybe image_url?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> title?: InputMaybe user_id?: InputMaybe } @@ -1183,16 +1246,10 @@ export type UsersEdge = { } export type UsersFilter = { - /** Returns true only if all its inner filters are true, otherwise returns false */ - and?: InputMaybe> email?: InputMaybe id?: InputMaybe name?: InputMaybe nodeId?: InputMaybe - /** Negates a filter */ - not?: InputMaybe - /** Returns true if at least one of its inner filters is true, otherwise returns false */ - or?: InputMaybe> profile_picture_url?: InputMaybe } @@ -1358,6 +1415,19 @@ export type DeleteTagMutation = { } } +export type DeleteTripMutationVariables = Exact<{ + id: Scalars['UUID']['input'] + userId: Scalars['UUID']['input'] +}> + +export type DeleteTripMutation = { + __typename: 'Mutation' + deleteFromtripsCollection: { + __typename: 'tripsDeleteResponse' + records: Array<{ __typename: 'trips'; id: string; title: string }> + } +} + export type DeleteTripTagMutationVariables = Exact<{ id: Scalars['UUID']['input'] }> @@ -1399,7 +1469,7 @@ export type TagsCollectionQuery = { } export type TripDetailsQueryVariables = Exact<{ - id: Scalars['UUID']['input'] + id?: InputMaybe }> export type TripDetailsQuery = { @@ -2358,6 +2428,114 @@ export const DeleteTagDocument = { } ] } as unknown as DocumentNode +export const DeleteTripDocument = { + __meta__: { hash: '6e8dd46bc33661ac768394595679671f8b605429' }, + kind: 'Document', + definitions: [ + { + kind: 'OperationDefinition', + operation: 'mutation', + name: { kind: 'Name', value: 'deleteTrip' }, + variableDefinitions: [ + { + kind: 'VariableDefinition', + variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } }, + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'UUID' } } + } + }, + { + kind: 'VariableDefinition', + variable: { + kind: 'Variable', + name: { kind: 'Name', value: 'userId' } + }, + type: { + kind: 'NonNullType', + type: { kind: 'NamedType', name: { kind: 'Name', value: 'UUID' } } + } + } + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: '__typename' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'deleteFromtripsCollection' }, + arguments: [ + { + kind: 'Argument', + name: { kind: 'Name', value: 'filter' }, + value: { + kind: 'ObjectValue', + fields: [ + { + kind: 'ObjectField', + name: { kind: 'Name', value: 'id' }, + value: { + kind: 'ObjectValue', + fields: [ + { + kind: 'ObjectField', + name: { kind: 'Name', value: 'eq' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'id' } + } + } + ] + } + }, + { + kind: 'ObjectField', + name: { kind: 'Name', value: 'user_id' }, + value: { + kind: 'ObjectValue', + fields: [ + { + kind: 'ObjectField', + name: { kind: 'Name', value: 'eq' }, + value: { + kind: 'Variable', + name: { kind: 'Name', value: 'userId' } + } + } + ] + } + } + ] + } + } + ], + selectionSet: { + kind: 'SelectionSet', + selections: [ + { kind: 'Field', name: { kind: 'Name', value: '__typename' } }, + { + kind: 'Field', + name: { kind: 'Name', value: 'records' }, + selectionSet: { + kind: 'SelectionSet', + selections: [ + { + kind: 'Field', + name: { kind: 'Name', value: '__typename' } + }, + { kind: 'Field', name: { kind: 'Name', value: 'id' } }, + { kind: 'Field', name: { kind: 'Name', value: 'title' } } + ] + } + } + ] + } + } + ] + } + } + ] +} as unknown as DocumentNode export const DeleteTripTagDocument = { __meta__: { hash: '1a4d048db574dedfebd859dc737e16a42021f3ff' }, kind: 'Document', @@ -2656,7 +2834,7 @@ export const TagsCollectionDocument = { ] } as unknown as DocumentNode export const TripDetailsDocument = { - __meta__: { hash: 'bbd255d8e0db3b7f99ea25021e5db3fcd72f4091' }, + __meta__: { hash: '1bc05beaca139a887f8c922c4de4dc6c86706670' }, kind: 'Document', definitions: [ { @@ -2667,10 +2845,7 @@ export const TripDetailsDocument = { { kind: 'VariableDefinition', variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } }, - type: { - kind: 'NonNullType', - type: { kind: 'NamedType', name: { kind: 'Name', value: 'UUID' } } - } + type: { kind: 'NamedType', name: { kind: 'Name', value: 'UUID' } } } ], selectionSet: { diff --git a/graphql-codegen/generated/persisted-documents.json b/graphql-codegen/generated/persisted-documents.json index b75687e..26cadb0 100644 --- a/graphql-codegen/generated/persisted-documents.json +++ b/graphql-codegen/generated/persisted-documents.json @@ -6,10 +6,11 @@ "68140ac8465fd7c6f5bab39db9eec02dab9501ef": "mutation createTrip($object: tripsInsertInput!) { __typename insertIntotripsCollection(objects: [$object]) { __typename records { __typename id title } } }", "b86b0c68b8ee2697ff1b539e5df92575cedb30f0": "mutation createTripTag($tagId: UUID!, $tripId: UUID!) { __typename insertIntotrip_tagsCollection(objects: [{trip_id: $tripId, tag_id: $tagId}]) { __typename records { __typename id tag_id trip_id } } }", "c661c9a00fdae1dbac69eeb283611e0c9202cf55": "mutation deleteTag($id: UUID!) { __typename deleteFromtagsCollection(filter: {id: {eq: $id}}) { __typename records { __typename id name } } }", + "6e8dd46bc33661ac768394595679671f8b605429": "mutation deleteTrip($id: UUID!, $userId: UUID!) { __typename deleteFromtripsCollection(filter: {id: {eq: $id}, user_id: {eq: $userId}}) { __typename records { __typename id title } } }", "1a4d048db574dedfebd859dc737e16a42021f3ff": "mutation deleteTripTag($id: UUID!) { __typename deleteFromtrip_tagsCollection(filter: {id: {eq: $id}}) { __typename records { __typename id } } }", "7b9783d44e5c70098239e977664434de3eae6204": "mutation updateTrip($id: UUID!, $set: tripsUpdateInput!) { __typename updatetripsCollection(set: $set, filter: {id: {eq: $id}}) { __typename records { __typename id title } } }", "994a2e7e0694c279cbfeff6c8696cbbe6a0c687c": "query tagsCollection($userId: UUID!) { __typename tagsCollection( filter: {user_id: {eq: $userId}} orderBy: {created_at: AscNullsLast} ) { __typename edges { __typename node { __typename id name } } } }", - "bbd255d8e0db3b7f99ea25021e5db3fcd72f4091": "query tripDetails($id: UUID!) { __typename tripsCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename address id time_from time_to title } } } cost cost_unit date_from date_to id image_url invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title trip_tagsCollection { __typename edges { __typename node { __typename tags { __typename id name } } } } } } } }", + "1bc05beaca139a887f8c922c4de4dc6c86706670": "query tripDetails($id: UUID) { __typename tripsCollection(filter: {id: {eq: $id}}) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename address id time_from time_to title } } } cost cost_unit date_from date_to id image_url invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title trip_tagsCollection { __typename edges { __typename node { __typename tags { __typename id name } } } } } } } }", "f4142b2a2f4ab96ce0e69488851fdff976486652": "query tripTagsCollection($filter: trip_tagsFilter) { __typename trip_tagsCollection(filter: $filter) { __typename edges { __typename node { __typename id tag_id trip_id } } } }", "3256c7ff43134c13502c53f475e55fa91f55cabb": "query tripsCollection($after: Cursor, $filter: tripsFilter, $first: Int!, $orderBy: [tripsOrderBy!]) { __typename tripsCollection( filter: $filter first: $first after: $after orderBy: $orderBy ) { __typename edges { __typename node { __typename activityCollection { __typename edges { __typename node { __typename id } } } created_at date_from date_to id id image_url invitationsCollection { __typename edges { __typename node { __typename users { __typename id profile_picture_url } } } } title } } pageInfo { __typename endCursor hasNextPage hasPreviousPage startCursor } } }" } From f9132af6e85e42693279559ecad893ca012941d8 Mon Sep 17 00:00:00 2001 From: Kana Taguchi Date: Tue, 6 Feb 2024 12:44:34 -0800 Subject: [PATCH 12/15] Change props --- app/trip/[id]/components/activity-card.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/trip/[id]/components/activity-card.tsx b/app/trip/[id]/components/activity-card.tsx index 2a4a2c6..5061025 100644 --- a/app/trip/[id]/components/activity-card.tsx +++ b/app/trip/[id]/components/activity-card.tsx @@ -170,7 +170,11 @@ export const ActivityCard = ({ activity, selectedDate }: ActivityCardProps) => { + Are you sure you want to delete this activity? + + } onClick={() => {}} submitLabel="Delete" /> From c63182036ea8c40232354ee401185b9410399caf Mon Sep 17 00:00:00 2001 From: Kana Taguchi Date: Tue, 6 Feb 2024 12:46:36 -0800 Subject: [PATCH 13/15] Delete unused code --- app/trip/hooks/useTagCreateDelete.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/trip/hooks/useTagCreateDelete.ts b/app/trip/hooks/useTagCreateDelete.ts index e93dc3f..0bcb54a 100644 --- a/app/trip/hooks/useTagCreateDelete.ts +++ b/app/trip/hooks/useTagCreateDelete.ts @@ -63,8 +63,7 @@ export const useTagCreateDelete = (tagsCollectionRefetch: () => void) => { await deleteTagMutation({ variables: { id: id - }, - refetchQueries: [] + } }) // refetch all tripDetails in case tag is used From a58133c00510a5362d88aa176560b8a059d62ce7 Mon Sep 17 00:00:00 2001 From: Sachi Goto <70562492+SachiGoto@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:40:32 -0800 Subject: [PATCH 14/15] adjusted css stylings based on feedback --- app/(auth)/change-password/page.tsx | 18 +++++++++++------- app/components/input/input-form.tsx | 6 +++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/app/(auth)/change-password/page.tsx b/app/(auth)/change-password/page.tsx index 5b2fa78..88cc5d9 100644 --- a/app/(auth)/change-password/page.tsx +++ b/app/(auth)/change-password/page.tsx @@ -68,20 +68,20 @@ export default function ChangePassword() { Change Password @@ -96,7 +96,7 @@ export default function ChangePassword() { {errors.oldPassword && ( {errors.oldPassword.message} @@ -104,21 +104,25 @@ export default function ChangePassword() { New Password - + {errors.newPassword && ( {errors.newPassword.message} )} Confirm New Password - + {errors.confirmNewPassword && ( {errors.confirmNewPassword.message} )} - + Change Password diff --git a/app/components/input/input-form.tsx b/app/components/input/input-form.tsx index e3b6e58..bac1e4e 100644 --- a/app/components/input/input-form.tsx +++ b/app/components/input/input-form.tsx @@ -11,10 +11,10 @@ import { import { FiEye, FiEyeOff } from 'react-icons/fi' type InputFormProps = { rightIcon?: IconType - showInput?: boolean + hasEyeIcon?: boolean } export const InputForm = forwardRef( - ({ rightIcon: RightIcon, showInput, ...props }, ref) => { + ({ rightIcon: RightIcon, hasEyeIcon, ...props }, ref) => { const bgColor = useColorModeValue('white', 'gray.700') const borderColor = useColorModeValue('gray.300', 'gray.500') const placeholdercolor = useColorModeValue('gray.400', 'gray.600') @@ -40,7 +40,7 @@ export const InputForm = forwardRef( )} - {showInput && ( + {hasEyeIcon && ( Date: Wed, 7 Feb 2024 20:09:50 -0800 Subject: [PATCH 15/15] fix input field --- app/(auth)/change-password/page.tsx | 24 ++++++++++++++++++------ app/components/input/input-form.tsx | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/(auth)/change-password/page.tsx b/app/(auth)/change-password/page.tsx index 88cc5d9..c3a305d 100644 --- a/app/(auth)/change-password/page.tsx +++ b/app/(auth)/change-password/page.tsx @@ -74,29 +74,33 @@ export default function ChangePassword() { Change Password Old Password {errors.oldPassword && ( {errors.oldPassword.message} @@ -104,14 +108,22 @@ export default function ChangePassword() { New Password - + {errors.newPassword && ( {errors.newPassword.message} )} Confirm New Password - + {errors.confirmNewPassword && ( {errors.confirmNewPassword.message} diff --git a/app/components/input/input-form.tsx b/app/components/input/input-form.tsx index bac1e4e..81c6b71 100644 --- a/app/components/input/input-form.tsx +++ b/app/components/input/input-form.tsx @@ -25,7 +25,7 @@ export const InputForm = forwardRef(