aws-amplify#API TypeScript Examples

The following examples show how to use aws-amplify#API. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: coaching.ts    From nyxo-app with GNU General Public License v3.0 6 votes vote down vote up
listCoaching = async (): Promise<CoachingItems | null> => {
  try {
    if (await isLoggedIn()) {
      const {
        data: { listCoachingDatas: data }
      } = (await API.graphql(graphqlOperation(listCoachingDatas))) as {
        data: ListCoachingDatasQuery
      }

      if (data?.items) {
        return data?.items
      }
      return []
    }
    return []
  } catch (error) {
    return error
  }
}
Example #2
Source File: bookmark-hooks.tsx    From nyxo-website with MIT License 6 votes vote down vote up
fetchLessonBookmarks = async (
  key: string,
  { slug }: { slug: string }
) => {
  try {
    const query: LikedContentBySlugQueryVariables = {
      slug: slug,
    }

    const {
      data: { likedContentBySlug: result },
    } = (await API.graphql(graphqlOperation(likedContentBySlug, query))) as {
      data: LikedContentBySlugQuery
    }

    if (!result || !result.items) return { bookmarked: false, id: "" }

    const { items } = result

    if (items?.length > 0) {
      return {
        bookmarked: true,
        id: items[0].id,
      }
    } else {
      return {
        bookmarked: false,
        id: "",
      }
    }
  } catch (error) {
    return error
  }
}
Example #3
Source File: events.ts    From platform with MIT License 6 votes vote down vote up
useEvents = () => {
  return useQuery("eventData", async () => {
    const yesterday = new Date(Date.now() - (3600 * 1000 * 24));
    const {
      data: {
        listEventsActive: { items: events },
      },
    } = await API.graphql({
      query: listEventsActive,
      variables: { active: "yes", startDate: { gt: yesterday } },
      authMode: "AWS_IAM",
    });

    const sorted = events.sort(
      (a, b) => new Date(a.startDate) - new Date(b.startDate)
    );

    return sorted.map((event) => ({
      ...event,
      name: event.name || event.type.name,
      description: event.description || event.type.description,
      time: event.time || event.type.time,
      maxEntries: event.maxEntries || event.type.maxEntries,
      color: event.type.color,
      url: event.type.url,
      isFull: event.entryCount >= (event.maxEntries || event.type.maxEntries)
    }));
  });
}
Example #4
Source File: bookmark-hooks.tsx    From nyxo-website with MIT License 6 votes vote down vote up
fetchAllBookmarks = async () => {
  try {
    const {
      data: { listLikedContents: result = { items: [] } },
    } = (await API.graphql(graphqlOperation(listLikedContents))) as {
      data: ListLikedContentsQuery
    }

    if (!result || !result.items) return []

    return result.items
  } catch (error) {
    return error
  }
}
Example #5
Source File: actions.tsx    From platform with MIT License 6 votes vote down vote up
export async function subscribe(dispatch, plan, stripe) {
  dispatch({ type: "LOADING" });
  const {
    attributes: { email },
  } = await Auth.currentAuthenticatedUser();
  const redirectTo = `${window.location.origin}/app/dashboard`;

  try {
    const { sessionId } = await API.post("public", "/checkout", {
      body: {
        plan,
        successUrl: redirectTo,
        cancelUrl: redirectTo,
        email,
      },
    });
    await stripe.redirectToCheckout({ sessionId });
  } catch (error) {
    dispatch({ type: "STOP_LOADING" });
    throw new Error("Unable to subscribe.");
  }
  dispatch({ type: "STOP_LOADING" });
}
Example #6
Source File: UserHabits.tsx    From nyxo-website with MIT License 6 votes vote down vote up
getHabits = async (): Promise<Array<Habit | null> | null | undefined> => {
  try {
    const response = (await API.graphql(graphqlOperation(listHabits, {}))) as {
      data: ListHabitsQuery
    }
    return response.data.listHabits?.items
  } catch (error) {
    console.warn(error)
    return undefined
  }
}
Example #7
Source File: sync.ts    From nyxo-app with GNU General Public License v3.0 6 votes vote down vote up
syncNights = createAsyncThunk<Response, Arguments>(
  'nights/sync',
  async ({ nights }, { rejectWithValue, dispatch, getState }) => {
    const input: CreateNightInput = {
      id,
      sourceId,
      sourceName,
      startDate,
      endDate,
      value: convertNightValue(value),
      userId: username,
      totalDuration
    }
    const _ = await API.graphql(graphqlOperation(createNight, { input }))

    try {
    } catch (error) {
      return rejectWithValue(false)
    }
  }
)
Example #8
Source File: member.ts    From platform with MIT License 6 votes vote down vote up
getMemberBySub = async (id) => {
  const {
    data: { getMember: member }
  } = await API.graphql({
    query: getMember,
    variables: { id },
    authMode: "AWS_IAM",
  });
  return member;
}
Example #9
Source File: coaching.ts    From nyxo-app with GNU General Public License v3.0 6 votes vote down vote up
getCoaching = async (
  _key: string,
  { id }: { id: string }
): Promise<GetCoachingDataQuery['getCoachingData']> => {
  try {
    const {
      data: { getCoachingData: data }
    } = (await API.graphql(graphqlOperation(getCoachingData, { id }))) as {
      data: GetCoachingDataQuery
    }

    return data
  } catch (error) {
    return error
  }
}
Example #10
Source File: Sensors.tsx    From aws-appsync-iot-core-realtime-dashboard with MIT No Attribution 6 votes vote down vote up
GetSensors = async (): Promise<Array<ISensor>> => {

    try {

        const response = (await API.graphql(graphqlOperation(listSensors))) as {
            data: ListSensorsQuery;
        };

        if (response.data && response.data.listSensors) {
            
            const r = response.data.listSensors as Array<ISensor>;
            
            return r;
        }
        else {

            return Array<ISensor>();
        }

    } catch (error) {
        throw error;
    }
}
Example #11
Source File: useUser.ts    From nyxo-website with MIT License 6 votes vote down vote up
getUserActiveCoaching = async (): Promise<
  GetActiveCoachingQuery["getUser"]
> => {
  try {
    const { username } = await Auth.currentUserInfo()
    const {
      data: { getUser: data },
    } = (await API.graphql(
      graphqlOperation(getActiveCoaching, { id: username })
    )) as {
      data: GetActiveCoachingQuery
    }
    return data
  } catch (error) {
    return error
  }
}
Example #12
Source File: AlbumScreen.tsx    From SpotifyClone with MIT License 6 votes vote down vote up
AlbumScreen = () => {

  const route = useRoute();
  const albumId = route.params.id;

  const [album, setAlbum] = useState(null)

  useEffect(() => {
    const fetchAlbumDetails = async () => {
      try {
        const data = await API.graphql(graphqlOperation(getAlbum, { id: albumId }))
        setAlbum(data.data.getAlbum)
      } catch (e) {
        console.log(e);
      }
    }

    fetchAlbumDetails();
  }, [])

  if (!album) {
    return <Text>Loading...</Text>
  }

  return (
    <View>
      <FlatList
        data={album.songs.items}
        renderItem={({ item }) => <SongListItem song={item} />}
        keyExtractor={(item) => item.id}
        ListHeaderComponent={() => <AlbumHeader album={album} />}
      />
    </View>
  )
}
Example #13
Source File: index.tsx    From TwitterClone with MIT License 6 votes vote down vote up
Feed = () => {

  const [tweets, setTweets] = useState([]);
  const [loading, setLoading] = useState(false);

  const fetchTweets = async () => {
    setLoading(true);
    try {
      const tweetsData = await API.graphql(graphqlOperation(listTweets));
      setTweets(tweetsData.data.listTweets.items);
    } catch (e) {
      console.log(e);
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    fetchTweets();
  }, [])

  return (
    <View style={{width: '100%'}}>
      <FlatList
        data={tweets}
        renderItem={({item}) => <Tweet tweet={item}/>}
        keyExtractor={(item) => item.id}
        refreshing={loading}
        onRefresh={fetchTweets}
        ListHeaderComponent={UserFleetsList}
      />
    </View>
  );
}
Example #14
Source File: bookmark-hooks.tsx    From nyxo-website with MIT License 6 votes vote down vote up
addBookmark = async ({ name, slug, type }: CreateLikedContentInput) => {
  if (isLoggedIn()) {
    try {
      const {
        data: { createLikedContent: response },
      } = (await API.graphql(
        graphqlOperation(createLikedContent, { input: { name, slug, type } })
      )) as { data: CreateLikedContentMutation }
      return response
    } catch (error) {
      return error
    }
  } else {
    navigate("/me/login")
  }
}
Example #15
Source File: Sensors.tsx    From aws-appsync-iot-core-realtime-dashboard with MIT No Attribution 6 votes vote down vote up
GetSensor = async (sensorId: string): Promise<ISensor | null> => {

    try {

        const response = (await API.graphql(graphqlOperation(getSensor, {sensorId: sensorId}))) as {
            data: GetSensorQuery;
        };

        if (response.data.getSensor){
            
            const r = response.data.getSensor as ISensor;
            
            return r;
        }
        else {

            return null;
        }

    } catch (error) {
        throw error;
    }
}
Example #16
Source File: bookmark-hooks.tsx    From nyxo-website with MIT License 6 votes vote down vote up
fetchWeekNLessonBookmarks = async (
  key: string,
  { initialLessons }: { initialLessons: ContentfulLesson[] }
) => {
  try {
    const {
      data: { listLikedContents: res },
    } = (await API.graphql(graphqlOperation(listLikedContents))) as {
      data: ListLikedContentsQuery
    }

    return initialLessons.map((lesson) => {
      if (res?.items?.some((item) => item?.slug === lesson.slug)) {
        return { ...lesson, bookmarked: true }
      } else {
        return lesson
      }
    })
  } catch (error) {
    console.log(error)
    return error
  }
}
Example #17
Source File: index.tsx    From TwitterClone with MIT License 6 votes vote down vote up
UserFleetsList = () => {

  const [users, setUsers] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const data = await API.graphql(graphqlOperation(listUsers));
        setUsers(data.data.listUsers.items);
      } catch (e) {
        console.log(e)
      }
    }
    fetchData();
  }, [])

  return (
    <View>
      <FlatList
        data={users}
        renderItem={({item}) => <UserFleetPreview user={item} />}
        horizontal
        showsHorizontalScrollIndicator={false}
      />
    </View>
  )
}
Example #18
Source File: chess.ts    From platform with MIT License 5 votes vote down vote up
getECFData = async (id) => {
  const response = await API.get("chessplayers",`/ecf/${id}`);
  return response;
}
Example #19
Source File: App.tsx    From Rapid-Application-Development-with-AWS-Amplify with MIT License 5 votes vote down vote up
App = () => {
  const [formState, setFormState] = useState(initialState);
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    fetchTodos();
  }, []);

  const setInput = (key: any, value: any):any => {
    setFormState({ ...formState, [key]: value });
  }

  const fetchTodos = async (): Promise<any> => {
    try {
      const todoData:any = await API.graphql(graphqlOperation(listTodos));
      const todos:any = todoData.data.listTodos.items;
      setTodos(todos);
    } catch (err) { 
      console.log('error fetching todos');
    }
  }

  const addTodo = async (): Promise<any> => {
    try {
      if (!formState.name || !formState.description) return;
      const todo = { ...formState };
      setTodos([...todos, todo] as SetStateAction<never[]>);
      setFormState(initialState);
      await API.graphql(graphqlOperation(createTodo, {input: todo}));
    } catch (err) {
      console.log('error creating todo:', err);
    }
  }

  return (
    <div className="container">
      <h2>Amplify Todos</h2>
      <input
        onChange={event => setInput('name', event.target.value)}
        value={formState.name} 
        placeholder="Name"
      />
      <input
        onChange={event => setInput('description', event.target.value)}
        value={formState.description}
        placeholder="Description"
      />
      <button onClick={addTodo}>Create Todo</button>
      {
        todos.map((todo: any, index: any) => (
          <div key={todo.id ? todo.id : index} className="todo">
            <p className="todoName">{todo.name}</p>
            <p className="todoDescription">{todo.description}</p>
          </div>
        ))
      }
    </div>
  )
}
Example #20
Source File: habit-actions.ts    From nyxo-app with GNU General Public License v3.0 5 votes vote down vote up
handleHabitsFromCloudWhenLoggingIn = (
  userId: string,
  merge: boolean
): AppThunk => async (dispatch, getState) => {
  const variables: {
    filter: ModelHabitFilterInput
    limit?: number
    nextToken?: string
  } = {
    filter: {
      userId: {
        eq: userId
      }
    }
  }

  try {
    const response = (await API.graphql(
      graphqlOperation(listHabits, variables)
    )) as {
      data: ListHabitsQuery
    }
    const cloudHabits = response.data.listHabits?.items
    const resultHabits = convertRemoteHabitsToLocalHabits(cloudHabits)
    const habits = getHabitsMap(getState())

    const promiseArray = []

    // If user does want to merge, we replace habitState.habits with concatenated on-cloud habits and current habitState.habits.
    if (merge) {
      habits.forEach((localHabit: Habit) => {
        // go through responsed items and merging local habits to see if there is any habits in commons
        const commonIndex = cloudHabits?.findIndex(
          (item) => item?.title?.trim() === localHabit.title.trim()
        )

        const syncingHabit: Habit = {
          ...localHabit,
          id: '',
          userId
        }

        // if the local habit is not stored in the cloud yet, we sync and merge it
        if (commonIndex === -1) {
          syncingHabit.id = v4() // Create new id for adding to cloud

          // Perform sync here
          promiseArray.push(
            dispatch(syncHabit(MutationType.CREATE, syncingHabit))
          )
        }
        // If the local habit is stored in the cloud, we update the cloud with the latest version of it (on-device/local)
        else {
          syncingHabit.id = cloudHabits[commonIndex].id // Keep the existing id

          // Perform sync here
          promiseArray.push(
            dispatch(syncHabit(MutationType.UPDATE, syncingHabit))
          )
        }

        // Perform merge here
        resultHabits.set(syncingHabit.id, syncingHabit)
      })
    }

    // Replace habitState.subHabits with old habitState.habits
    promiseArray.push(dispatch(replaceSubHabits(habits)))
    // Replace current habitState.habits with the result map
    promiseArray.push(dispatch(replaceHabits(resultHabits)))
    await Promise.all(promiseArray)
  } catch (error) {
    Sentry.captureException(error)

    await dispatch(toggleMergingDialog(false))
  }
}
Example #21
Source File: App.tsx    From Rapid-Application-Development-with-AWS-Amplify with MIT License 5 votes vote down vote up
App = () => {
  const [formState, setFormState] = useState(initialState);
  const [todos, setTodos] = useState<any[]>([]);

  useEffect(() => {
    fetchTodos();
  }, []);

  const setInput = (key: any, value: any):any => {
    setFormState({ ...formState, [key]: value });
  }

  const fetchTodos = async (): Promise<any> => {
    try {
      const todoData:any = await API.graphql(graphqlOperation(listTodos));
      const todos:any = todoData.data.listTodos.items;
      setTodos(todos);
    } catch (err) { 
      console.log('error fetching todos');
    }
  }

  const addTodo = async (): Promise<any> => {
    try {
      if (!formState.name || !formState.description) return;
      const todo = { ...formState };
      setTodos([...todos, todo] as SetStateAction<any[]>);
      setFormState(initialState);
      await API.graphql(graphqlOperation(createTodo, {input: todo}));
    } catch (err) {
      console.log('error creating todo:', err);
    }
  }

  return (
    <View style={styles.container}>
      <TextInput
        onChangeText={val => setInput('name', val)}
        style={styles.input}
        value={formState.name} 
        placeholder="Name"
      />
      <TextInput
        onChangeText={val => setInput('description', val)}
        style={styles.input}
        value={formState.description}
        placeholder="Description"
      />
      <Button title="Create Todo" onPress={addTodo} />
      {
        todos.map((todo, index) => (
          <View key={todo.id ? todo.id : index} style={styles.todo}>
            <Text style={styles.todoName}>{todo.name}</Text>
            <Text>{todo.description}</Text>
          </View>
        ))
      }
    </View>
  )
}
Example #22
Source File: bookmark-hooks.tsx    From nyxo-website with MIT License 5 votes vote down vote up
fetchHabitBookmarks = async () => {
  return (await API.graphql(
    graphqlOperation(listLikedContents, { filter: { type: { eq: "habit" } } })
  )) as { data: ListLikedContentsQuery }
}
Example #23
Source File: chess.ts    From platform with MIT License 5 votes vote down vote up
getPlayerGames = async (id) => {
  const response = await API.get("chessplayers",`/games/${id}/Standard`);
  return response;
}
Example #24
Source File: BottomTabNavigator.tsx    From TwitterClone with MIT License 5 votes vote down vote up
function HomeNavigator() {

  const [user, setUser] = useState(null);

  useEffect(() => {
    // get the current user
    const fetchUser = async () => {
      const userInfo = await Auth.currentAuthenticatedUser({ bypassCache: true });
      if (!userInfo) {
        return;
      }

      try {
        const userData = await API.graphql(graphqlOperation(getUser, { id: userInfo.attributes.sub }))
        if (userData) {
          setUser(userData.data.getUser);
        }
      } catch (e) {
        console.log(e);
      }
    }
    fetchUser();
  }, [])

  return (
    <TabOneStack.Navigator>
      <TabOneStack.Screen
        name="HomeScreen"
        component={HomeScreen}
        options={{
          headerRightContainerStyle: {
            marginRight: 15,
          },
          headerLeftContainerStyle: {
            marginLeft: 15,
          },
          headerTitle: () => (
            <Ionicons name={"logo-twitter"} size={30} color={Colors.light.tint}/>
          ),
          headerRight: () => (
            <MaterialCommunityIcons name={"star-four-points-outline"} size={30} color={Colors.light.tint}/>
          ),
          headerLeft: () => (
            <ProfilePicture size={40} image={user?.image} />
          )
        }}
      />
    </TabOneStack.Navigator>
  );
}
Example #25
Source File: useApi.ts    From crossfeed with Creative Commons Zero v1.0 Universal 5 votes vote down vote up
useApi = (onError?: OnError) => {
  const [requestCount, setRequestCount] = useState(0);

  const getToken = () => {
    const t = localStorage.getItem('token');
    try {
      return t ? JSON.parse(t) : '';
    } catch {
      return '';
    }
  };

  const prepareInit = useCallback(async (init: any) => {
    const { headers, ...rest } = init;
    return {
      ...rest,
      headers: {
        ...headers,
        ...baseHeaders,
        Authorization: getToken()
      }
    };
  }, []);

  const { trackEvent } = useMatomo();

  const apiMethod = useCallback(
    (method: ApiMethod, methodName: string) => async <T extends object = any>(
      path: string,
      init: any = {}
    ) => {
      const { showLoading = true, ...rest } = init;
      try {
        trackEvent({
          category: 'apiMethod',
          action: methodName,
          name: path,
          documentTitle: document.title
        });
        showLoading && setRequestCount((cnt) => cnt + 1);
        const options = await prepareInit(rest);
        const result = await method('crossfeed', path, options);
        showLoading && setRequestCount((cnt) => cnt - 1);
        return result as T;
      } catch (e) {
        showLoading && setRequestCount((cnt) => cnt - 1);
        onError && onError(e);
        throw e;
      }
    },
    // Adding trackEvent to deps causes an infinite loop.
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [prepareInit, onError]
  );

  const api = {
    apiGet: useMemo(() => apiMethod(API.get.bind(API), 'get'), [apiMethod]),
    apiPost: useMemo(() => apiMethod(API.post.bind(API), 'post'), [apiMethod]),
    apiDelete: useMemo(() => apiMethod(API.del.bind(API), 'del'), [apiMethod]),
    apiPut: useMemo(() => apiMethod(API.put.bind(API), 'put'), [apiMethod]),
    apiPatch: useMemo(() => apiMethod(API.patch.bind(API), 'patch'), [
      apiMethod
    ])
  };

  return {
    ...api,
    loading: requestCount > 0
  };
}
Example #26
Source File: bookmark-hooks.tsx    From nyxo-website with MIT License 5 votes vote down vote up
fetchWeekBookmarks = async () => {
  const { data } = (await API.graphql(graphqlOperation(listLikedContents))) as {
    data: ListLikedContentsQuery
  }

  return data
}
Example #27
Source File: App.tsx    From TwitterClone with MIT License 5 votes vote down vote up
function App() {
  const isLoadingComplete = useCachedResources();
  const colorScheme = useColorScheme();

  const getRandomImage = () => {
    return 'https://scontent.fkiv3-1.fna.fbcdn.net/v/t31.0-8/s960x960/22256588_1932617800312085_5686197942193420542_o.jpg?_nc_cat=110&_nc_sid=85a577&_nc_ohc=svjjE7DUkc0AX9yjcdC&_nc_ht=scontent.fkiv3-1.fna&tp=7&oh=1df4116c73c45a32ebad070704ca3333&oe=5F6ECD77'
  }

  const saveUserToDB = async (user) => {
    console.log(user);
    await API.graphql(graphqlOperation(createUser, { input: user }))
  }

  useEffect(() => {
    const updateUser = async () => {
      // Get current authenticated user
      const userInfo = await Auth.currentAuthenticatedUser({ bypassCache: true });

      if(userInfo) {
        // Check if user already exists in database
        const userData = await API.graphql(graphqlOperation(getUser, { id: userInfo.attributes.sub }));
        console.log(userData)
        if(!userData.data.getUser) {
          const user = {
            id: userInfo.attributes.sub,
            username: userInfo.username,
            name: userInfo.username,
            email: userInfo.attributes.email,
            image: getRandomImage(),
          }
          await saveUserToDB(user);
        } else {
          console.log('User already exists');
        }
      }


      // If it doesn't, create the user in the database
    }
    updateUser();
  }, [])

  if (!isLoadingComplete) {
    return null;
  } else {
    return (
      <SafeAreaProvider>
        <Navigation colorScheme={colorScheme} />
        <StatusBar />
      </SafeAreaProvider>
    );
  }
}
Example #28
Source File: bookmark-hooks.tsx    From nyxo-website with MIT License 5 votes vote down vote up
fetchUserBookmarks = async (
  key: string,
  { content }: { content: ContentData }
) => {
  try {
    const {
      data: { listLikedContents: result },
    } = (await API.graphql(graphqlOperation(listLikedContents))) as {
      data: ListLikedContentsQuery
    }

    if (!result || !result?.items) return null
    const { items: bookmarks } = result

    // Use forEach instead of map to handle cases where static data does not mach user data (e.g. user has liked new content which does not exist on site yet)
    const weeks: ContentfulWeek[] = []
    const lessons: ContentfulLesson[] = []
    const habits: ContentfulHabit[] = []

    bookmarks.forEach((bookmark) => {
      const extraData = content.find((item) => item.slug === bookmark?.slug)
      if (extraData) {
        switch (bookmark?.type) {
          case "habit":
            habits.push({ ...bookmark, ...extraData })
            break
          case "lesson":
            lessons.push({ ...bookmark, ...extraData })
            break
          case "week":
            weeks.push({ ...bookmark, ...extraData })
            break
          default:
            break
        }
      }
    })

    return {
      weeks,
      lessons,
      habits,
    }
  } catch (error) {
    console.log(error)

    return error
  }
}
Example #29
Source File: Form.tsx    From project-papua with Apache License 2.0 4 votes vote down vote up
Form: React.FC<{}> = () => {
  const { form, translateByID, translateCopy, completion, pageIndex, setPage, values } = useContext(FormContext)
  const size = useContext(ResponsiveContext)

  const [canSubmit, setCanSubmit] = useState(true)
  const [claimID, setClaimID] = useState<string>()

  const onSubmit = async () => {
    setCanSubmit(false)
    try {
      /**
       * TODO: clear any subquestion values if the subquestion is hidden, s.t. we don't submit those values.
       *
       * We should only do this at submission time, so that users can toggle switches without losing
       * their WIP content.
       */
      const resp = await API.post('resolverAPI', '/claims', {
        body: {
          metadata: {
            uuid: uuid(window.location.hostname, uuid.DNS),
            timestamp: new Date(),
            host: window.location.hostname,
          },
          questions: values,
        },
      })
      console.log(resp)
      setClaimID(resp.id)
    } catch (err) {
      setCanSubmit(true)
      console.error(JSON.stringify(err.response.data, null, 2))
    }
  }

  const pageTitles = [...form.pages.map((page) => translateCopy(page.title)), translateByID('submit')]

  const padding = size === 'small' ? '12px' : '24px'
  const pageComponents = [
    ...form.pages.map((page) => (
      <Box
        pad={{ horizontal: padding, top: padding, bottom: 'none' }}
        direction="column"
        justify="start"
        key={page.heading.en}
      >
        <Heading margin="none" level={3}>
          {translateCopy(page.heading)}
        </Heading>
        {page.instructions && <Markdown size="small">{translateCopy(page.instructions)}</Markdown>}
        <Box margin={{ bottom: 'medium' }}></Box>
        {page.questions.map((question) => (
          <Question question={question} key={question.id} />
        ))}
      </Box>
    )),
    <Review key="review" pages={form.pages} />,
  ]

  const onClickNext = () => setPage(pageIndex + 1)
  const onClickBack = () => setPage(pageIndex - 1)

  return (
    <Box align="center" pad="medium" direction="column" width="100%" style={{ maxWidth: '1200px' }}>
      <Box width="100%" height="100%" justify="center" direction={size === 'small' ? 'column' : 'row'}>
        <Card pad="medium" justify="between" flex={{ grow: 1, shrink: 1 }}>
          {(claimID && <Confirmation id={claimID} />) || (
            <>
              {pageComponents[pageIndex]}
              <Box justify="between" pad="medium" direction="row">
                {(pageIndex > 0 && (
                  <Button onClick={onClickBack} label={translateByID('back')} icon={<FormPrevious />} />
                )) || <Box />}
                {pageIndex + 1 < pageTitles.length && (
                  <Button
                    primary={pageIndex === 0}
                    onClick={onClickNext}
                    disabled={!completion[pageIndex]}
                    icon={<FormNext />}
                    reverse={true}
                    label={pageIndex === 0 ? translateByID('get-started') : translateByID('next')}
                  />
                )}
                {pageIndex === pageTitles.length - 1 && (
                  <Button
                    primary={true}
                    onClick={onSubmit}
                    disabled={!canSubmit}
                    label={translateByID('submit:button')}
                  />
                )}
              </Box>
            </>
          )}
        </Card>
        <Sidebar pages={pageTitles} />
      </Box>
    </Box>
  )
}