FindMyRecipe / src / routes / Home.svelte
Home.svelte
Raw
<script>
  import PaginationWrapper from '../lib/components/PaginationWrapper.svelte'
  import AutocompleteSearch from '../lib/components/AutocompleteSearch.svelte'
  import { matchRecipes } from '../lib/utils/recipes.js'
  import {
    autocompleteIngredients,
    getIngredientByName,
  } from '../lib/utils/ingredients.js'
  import {
    getTagsOfRecipe,
    getTagByName,
    autocompleteTags,
  } from '../lib/utils/tags.js'
  import { ENTER_KEY } from '../lib/utils/utils.js'

  let loaded = false
  let searchBar = ''
  let fridge = []
  let tags = []
  let recipes = []
  let searchMatches = []
  let matchedTags = []
  let searchStatus = ''
  let inputTimeout = null

  const handleAutoCompTO = (e) => {
    clearTimeout(inputTimeout)

    if (e.keyCode == ENTER_KEY) {
      handleInputEnd()
      return
    }
    inputTimeout = setTimeout(async () => {
      searchBar = searchBar.trim()
      await handleAutoComp()
    }, 200)
  }

  const setInputVal = (input) => {
    if (searchBar != '' && searchBar[0] == '#') {
      !tags.includes(input) ? tags.push(input) : ''
      tags = tags
    } else {
      !fridge.includes(input) ? fridge.push(input) : ''
      fridge = fridge
    }
    searchBar = ''
    searchMatches = []
  }

  const mapTags = async (tagNames) => {
    let ids = []
    ids = await Promise.all(
      tagNames.map(async (i) => {
        console.log(i)
        return (await getTagByName(i)).data.id
      }),
    )
    console.log('tagIds: ', ids)
    return ids
  }

  const mapIngredients = async (ingredientNames) => {
    let ids = []
    ids = await Promise.all(
      ingredientNames.map(async (i) => {
        console.log(i)
        return (await getIngredientByName(i)).data.id
      }),
    )
    console.log('ingredientIds: ', ids)
    return ids
  }

  const handleAutoComp = async () => {
    searchMatches = []
    searchStatus = ''
    let response
    if (searchBar == '') {
      return
    } else if (searchBar[0] == '#') {
      response = await autocompleteTags(searchBar.substring(1))
    } else {
      response = await autocompleteIngredients(searchBar)
    }

    if (response.data == null) {
      return
    }
    response.data.forEach((i) => {
      searchMatches.push(i.name)
    })
    searchMatches = searchMatches
  }

  const searchRecipes = async () => {
    loaded = false
    recipes = []
    let req = await Promise.all([mapIngredients(fridge), mapTags(tags)])
    console.log(req[0], req[1])
    let res = await matchRecipes(req[0], req[1])
    console.log(res)
    if (res.status == 'success') {
      recipes = res.data
      let ptags = await Promise.all(
        recipes.map(async (r) => {
          return (await getTagsOfRecipe(r.Id)).data
        }),
      )
      matchedTags = ptags
      console.log(matchedTags)
      loaded = true
    } else {
      searchStatus = res.message
    }
  }

  const handleInputEnd = () => {
    let isIngredient = true
    let input = searchBar
    if (searchBar != '' && searchBar[0] == '#') {
      isIngredient = false
      input = searchBar.substring(1)
    }
    if (searchMatches.length == 1) {
      input = searchMatches[0]
    }
    if (searchMatches.includes(input)) {
      if (isIngredient && !fridge.includes(input)) {
        fridge.push(input)
      } else if (!isIngredient && !tags.includes(input)) {
        tags.push(input)
      }
    } else {
      return
    }
    searchBar = ''
    fridge = fridge
    tags = tags
    searchMatches = []
  }

  const removeFromFridge = (ing) => {
    const index = fridge.indexOf(ing)
    if (index > -1) {
      fridge.splice(index, 1)
    }
    fridge = fridge
  }

  const removeFromTags = (tag) => {
    const index = tags.indexOf(tag)
    if (index > -1) {
      tags.splice(index, 1)
    }
    tags = tags
  }

  const stopSuggestion = () => {
    searchMatches = []
  }

  $: searchBarMargin = recipes.length == 0 ? 'hidden' : 'h-20'
  let page = 1;
</script>

<div on:click={stopSuggestion}>
  <div class="hero min-h-screen bg-base-200">
    <div class="flex flex-col hero-content p-0 text-center">
      <div class="flex flex-grow {searchBarMargin}"></div>
      <div class="max-w-xl">
        <h1 class="text-5xl font-bold">Find What You Can Cook</h1>
        <p class="py-6">
          Just type your ingredients, and we'll show you what YOU can cook!
        </p>
        <div class="form-control items-center">
          <!-- <SearchBar /> -->
          <!-- QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ -->

          <div class="input-group">
            <input
              on:click={() => {
                handleInputEnd()
              }}
              bind:value={searchBar}
              type="text"
              placeholder="Type ingredients and/or add a '#' in front to filter by tags"
              class="input input-bordered w-full"
            />
            <button
              on:click={async () => {
                await searchRecipes()
              }}
              class="btn btn-square"
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                class="h-6 w-6"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
                ><path
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  stroke-width="2"
                  d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
                /></svg
              >
            </button>
          </div>

          <!-- ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ -->

          <div class="fridge-tags">
            <br style="margin-bottom:0" />
            {#if tags.length > 0}
              <ul class="">
                {#each tags as tag, i}
                  <div class="badge gap-2 badge-lg">
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      fill="none"
                      viewBox="0 0 24 24"
                      class="inline-block w-4 h-4 stroke-current"
                      on:click={() => removeFromTags(tag)}
                      ><path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M6 18L18 6M6 6l12 12"
                      /></svg
                    >
                    #{tag}
                  </div>
                {/each}
              </ul>
            {/if}
            {#if fridge.length > 0}
              <ul class="">
                {#each fridge as ing, i}
                  <div class="badge badge-outline badge-lg gap-2">
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      fill="none"
                      viewBox="0 0 24 24"
                      class="inline-block w-4 h-4 stroke-current"
                      on:click={() => removeFromFridge(ing)}
                      ><path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        stroke-width="2"
                        d="M6 18L18 6M6 6l12 12"
                      /></svg
                    >
                    {ing}
                  </div>
                {/each}
              </ul>
            {/if}
          </div>
          <!-- WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW -->
        </div>
      </div>
      {#if searchMatches.length > 0}
        <ul>
          {#each searchMatches as ingredient, i}
            <div
              class="btn btn-ghost btn-wide normal-case"
              on:click={() => setInputVal(ingredient)}
            >
              <li>{ingredient}</li>
            </div>
          {/each}
        </ul>
      {/if}
      <div class="w-screen">
        {#await searchRecipes}
          <div class="flex justify-center text-2xl mt-3">
            Loading...
          </div>
        {:then}
          {#if loaded == true && recipes.length > 0}
            <PaginationWrapper 
              recipes={recipes} 
              tags={matchedTags} 
              page={page}
              totalPages={Math.ceil(recipes.length / 6)}
            />
          {:else}
            {searchStatus}
          {/if}
        {/await}
      </div>
    </div>
  </div>
</div>

<svelte:window
  on:keyup={(e) => {
    handleAutoCompTO(e)
  }}
/>