From bf6e2cf93b595d2411a8a237f826adb8261d5f51 Mon Sep 17 00:00:00 2001 From: Jonathon Herbert Date: Mon, 29 Apr 2024 12:51:25 +0100 Subject: [PATCH] Add RecipeFeedItem component, and wire into RecipeSearchContainer --- .../src/bundles/fixtures/recipe1.json | 424 ++++++++++++++++++ .../src/bundles/fixtures/recipe2.json | 154 +++++++ fronts-client/src/bundles/recipesBundle.ts | 18 +- .../src/components/feed/FeedItem.tsx | 1 + .../src/components/feed/RecipeFeedItem.tsx | 31 ++ .../components/feed/RecipeSearchContainer.tsx | 3 +- fronts-client/src/types/Recipe.ts | 2 + 7 files changed, 617 insertions(+), 16 deletions(-) create mode 100644 fronts-client/src/bundles/fixtures/recipe1.json create mode 100644 fronts-client/src/bundles/fixtures/recipe2.json diff --git a/fronts-client/src/bundles/fixtures/recipe1.json b/fronts-client/src/bundles/fixtures/recipe1.json new file mode 100644 index 00000000000..cb4bc311d4e --- /dev/null +++ b/fronts-client/src/bundles/fixtures/recipe1.json @@ -0,0 +1,424 @@ +{ + "bookCredit": "", + "canonicalArticle": "food/2022/oct/15/make-your-own-chinese-dumplings-yotam-ottolenghi-recipes-shanghai-buns", + "celebrationIds": [], + "composerId": "633429038f086841b84c39a5", + "contributors": [ + "profile/yotamottolenghi" + ], + "cuisineIds": [], + "description": "The words “crab” and “butterscotch” aren’t often put together, but trust me on this one. Mixed with egg or mayonnaise, this also makes a great tart or sandwich filling, incidentally.", + "featuredImage": { + "url": "https://i.guim.co.uk/img/media/67f51e74f91032bd893349aa3a8c66ad55659bdd/30_111_2949_3201/master/2949.jpg?width=1600&dpr=1&s=none", + "mediaId": "67f51e74f91032bd893349aa3a8c66ad55659bdd", + "cropId": "30_111_2949_3201", + "source": "The Guardian", + "photographer": "Louise Hagger", + "imageType": "\"Photograph\"", + "caption": "Yotam Ottolenghi’s white crab and cabbage buns with brown crab butterscotch.", + "width": 2949, + "height": 3201, + "displayCredit": true + }, + "id": "ae779e4975904ba6a601449e513d88f7", + "ingredients": [ + { + "ingredientsList": [ + { + "amount": { + "min": 300, + "max": 300 + }, + "name": "white bread flour", + "optional": false, + "prefix": "strong", + "suffix": "plus 1½ tbsp extra for dusting", + "unit": "g" + }, + { + "amount": { + "min": 1, + "max": 1 + }, + "name": "dried yeast", + "optional": false, + "prefix": "fast-action", + "unit": "tsp" + }, + { + "amount": { + "min": 0.5, + "max": 0.5 + }, + "name": "caster sugar", + "optional": false, + "unit": "tsp" + }, + { + "amount": { + "min": 0.5, + "max": 0.5 + }, + "name": "baking powder", + "optional": false, + "unit": "tsp" + }, + { + "amount": { + "min": 0.25, + "max": 0.25 + }, + "name": "salt", + "optional": false, + "unit": "tsp" + }, + { + "amount": { + "min": 0.5, + "max": 0.5 + }, + "name": "sesame oil", + "optional": false, + "unit": "tsp" + }, + { + "amount": { + "min": 175, + "max": 175 + }, + "name": "water", + "optional": false, + "prefix": "lukewarm", + "unit": "ml" + }, + { + "amount": { + "min": 350, + "max": 400 + }, + "name": "filling", + "optional": false, + "suffix": "see below", + "unit": "g" + }, + { + "amount": { + "min": 3, + "max": 3 + }, + "name": "vegetable oil", + "optional": false, + "unit": "tbsp" + }, + { + "amount": { + "min": 1, + "max": 1 + }, + "name": "star anise", + "optional": false + }, + { + "amount": { + "min": null, + "max": null + }, + "name": "Dipping sauce", + "optional": false, + "suffix": "or black rice vinegar, to serve" + } + ], + "recipeSection": "For the buns" + }, + { + "ingredientsList": [ + { + "amount": { + "max": 350, + "min": 350 + }, + "name": "chinese", + "optional": false, + "suffix": "(or napa) cabbage, shredded", + "text": "350 g chinese (or napa) cabbage, shredded", + "unit": "g" + }, + { + "name": "Fine sea salt", + "optional": false, + "suffix": "and black pepper", + "text": "Fine sea salt and black pepper" + }, + { + "amount": { + "max": 200, + "min": 200 + }, + "name": "white crab meat", + "optional": false, + "text": "200 g white crab meat", + "unit": "g" + }, + { + "amount": { + "max": 1, + "min": 1 + }, + "name": "tarragon leaves", + "optional": false, + "suffix": "roughly chopped", + "text": "1 tsp tarragon leaves, roughly chopped", + "unit": "tsp" + }, + { + "amount": { + "max": 2, + "min": 2 + }, + "name": "chives", + "optional": false, + "suffix": "finely chopped", + "text": "2 tbsp chives, finely chopped", + "unit": "tbsp" + }, + { + "amount": { + "max": 1, + "min": 1 + }, + "name": "coriander", + "optional": false, + "suffix": "finely chopped", + "text": "1 tbsp coriander, finely chopped", + "unit": "tbsp" + }, + { + "amount": { + "max": 2, + "min": 2 + }, + "name": "light soy sauce", + "optional": false, + "text": "2 tsp light soy sauce", + "unit": "tsp" + }, + { + "amount": { + "max": 2, + "min": 2 + }, + "name": "fish sauce", + "optional": false, + "text": "2 tsp fish sauce", + "unit": "tsp" + }, + { + "amount": { + "max": 30, + "min": 30 + }, + "name": "unsalted butter", + "optional": false, + "suffix": "melted", + "text": "30 g unsalted butter, melted", + "unit": "g" + }, + { + "amount": { + "max": 1, + "min": 1 + }, + "name": "honey", + "optional": false, + "text": "1 tsp honey", + "unit": "tsp" + }, + { + "amount": { + "max": 2, + "min": 2 + }, + "name": "plain flour", + "optional": false, + "text": "2 tsp plain flour", + "unit": "tsp" + }, + { + "amount": { + "max": 1, + "min": 1 + }, + "name": "lime", + "optional": false, + "suffix": "zest finely grated, to get 1 tsp, then cut into 6 wedges", + "text": "1 lime, zest finely grated, to get 1 tsp, then cut into 6 wedges" + } + ], + "recipeSection": "For the filling" + }, + { + "ingredientsList": [ + { + "amount": { + "max": 40, + "min": 40 + }, + "name": "unsalted butter", + "optional": false, + "text": "40 g unsalted butter", + "unit": "g" + }, + { + "amount": { + "max": 2, + "min": 2 + }, + "name": "demerara sugar", + "optional": false, + "text": "2 tsp demerara sugar", + "unit": "tsp" + }, + { + "amount": { + "max": 1, + "min": 1 + }, + "name": "soy sauce", + "optional": false, + "text": "1 tsp soy sauce", + "unit": "tsp" + }, + { + "amount": { + "max": 0.5, + "min": 0.5 + }, + "name": "red chilli", + "optional": false, + "suffix": "(5g), stem, pith and seeds removed, flesh roughly chopped", + "text": "½ red chilli (5 g), stem, pith and seeds removed, flesh roughly chopped" + }, + { + "amount": { + "max": 50, + "min": 50 + }, + "name": "brown crab meat", + "optional": false, + "text": "50 g brown crab meat", + "unit": "g" + }, + { + "amount": { + "max": 0.5, + "min": 0.5 + }, + "name": "lime juice", + "optional": false, + "text": "½ tsp lime juice", + "unit": "tsp" + } + ], + "recipeSection": "For the crab butterscotch" + } + ], + "instructions": [ + { + "description": "Put the first five ingredients in the bowl of a stand mixer fitted with the dough hook, keeping the yeast and salt separate and on opposite sides. Mix on a medium speed, then beat in the sesame oil and 175ml of lukewarm water until it forms a dough. Turn up the speed to medium-high and mix for 10 minutes more, until smooth and pliable. Shape the dough into a ball, return to the mixer bowl, cover with a damp cloth and put in a warm place for about 50 minutes to an hour, to prove until doubled in size." + }, + { + "description": "In the meantime, make the filling. Put the cabbage in a large colander set over a bowl, sprinkle over an eighth of a teaspoon of salt, mix well and leave for 20 minutes. Working one handful at a time, squeeze to extract as much water from the cabbage as possible, then put the shredded cabbage in a large bowl with all the other stuffing ingredients and a good grind of black pepper. Mix well and refrigerate for 20 minutes" + }, + { + "description": "Make the crab butterscotch. Put the butter, sugar, soy, chilli and an eighth of a teaspoon of salt in a small saucepan on a medium-high heat. Simmer for 90 seconds, until thick and glossy, then take off the heat. Add the brown crab meat, lime juice and a teaspoon of water, and stir until silky and well mixed in" + }, + { + "description": "Take the risen dough out of the bowl and put it on a lightly floured work surface. Knead well to knock out all the air, then roll into a 4cm-wide sausage. Cut this into 15 pieces of about 30g each, then, using a rolling pin, roll each piece into a 3mm-thick, 9cm-diameter disc and flour generously" + }, + { + "description": "To shape the buns, put one disc in the palm of your non-dominant hand and put a spoonful of your filling. Use your other hand to lift the edges of the disc up and over the filling, so they meet at the top and enclose it. Use your fingers to twist and seal the top edges together, so it now looks like a money bag. Pinch and twist the peak into a spiral, then tear off and discard the top half-centimetre of dough. Put the dough spiral side down on a lightly floured surface and repeat with the remaining discs of bun dough" + }, + { + "description": "To cook the filled buns, put the vegetable oil in a large (28cm), nonstick frying pan for which you have a lid on a medium-high heat. Once it’s hot, take off the heat and carefully arrange the buns seam side down in the pan, so they cover its base; it’s OK if they touch slightly, but you don’t want them to be snug. Return the pan to the heat and fry the buns for two minutes, until golden and starting to crisp up underneath. Taking great care – it might spit! – pour 160ml boiling water around the edges of the pan (ie, not over the buns), add the star anise, cover the pan with its lid and leave to steam for six minutes. Remove the lid and carry on cooking uncovered until all the water has evaporated and the buns are cooked through" + }, + { + "description": "Turn off the heat and use tongs carefully to lift each bun fried side up on to a large plate. Serve with your favourite dipping sauce or a small bowl of black rice vinegar" + } + ], + "isAppReady": false, + "mealTypeIds": [ + "lunch", + "side", + "snack" + ], + "serves": [ + { + "amount": { + "min": 15, + "max": 15 + }, + "unit": "servings" + } + ], + "suitableForDietIds": [ + "pescatarian", + "meat-free" + ], + "techniquesUsedIds": [], + "timings": [ + { + "durationInMins": { + "min": 20, + "max": 20 + }, + "qualifier": "prep-time", + "text": "Prep 10 min" + }, + { + "durationInMins": { + "min": 50, + "max": 50 + }, + "qualifier": "prove-time" + }, + { + "durationInMins": { + "max": 20, + "min": 20 + }, + "qualifier": "steep-time", + "text": "Steep 20 min" + }, + { + "durationInMins": { + "max": 20, + "min": 20 + }, + "qualifier": "chill-time", + "text": "Chill 20 min" + }, + { + "durationInMins": { + "min": 90, + "max": 90 + }, + "qualifier": "cook-time", + "text": "Cook 30 min" + } + ], + "title": "White crab and cabbage buns with brown crab butterscotch", + "utensilsAndApplianceIds": [], + "byline": [], + "previewImage": { + "url": "https://i.guim.co.uk/img/media/67f51e74f91032bd893349aa3a8c66ad55659bdd/30_111_2949_3201/master/2949.jpg?width=1600&dpr=1&s=none", + "mediaId": "67f51e74f91032bd893349aa3a8c66ad55659bdd", + "cropId": "30_111_2949_3201", + "source": "The Guardian", + "photographer": "Louise Hagger", + "imageType": "\"Photograph\"", + "caption": "Yotam Ottolenghi’s white crab and cabbage buns with brown crab butterscotch.", + "width": 2949, + "height": 3201, + "displayCredit": true + } +} diff --git a/fronts-client/src/bundles/fixtures/recipe2.json b/fronts-client/src/bundles/fixtures/recipe2.json new file mode 100644 index 00000000000..a61578d3b2d --- /dev/null +++ b/fronts-client/src/bundles/fixtures/recipe2.json @@ -0,0 +1,154 @@ +{ + "bookCredit": "", + "canonicalArticle": "lifeandstyle/2015/feb/20/cauliflower-recipes-yotam-ottolenghi", + "celebrationIds": [], + "composerId": "54d0b9b2e4b00c561b82de60", + "contributors": [ + "profile/yotamottolenghi" + ], + "cuisineIds": [], + "description": "I like to serve this in the centre of the table, for people to share with drinks at the start of a meal. We break the cauliflower apart with our hands (let it cool down a little first), dip the individual florets and crisp green leaves into the creme fraiche sauce and sprinkle with salt", + "featuredImage": { + "url": "https://i.guim.co.uk/img/media/9428c177111fcaea066fce717cdb74b9779466e7/0_18_3379_4225/master/3379.jpg?width=1600&dpr=1&s=none", + "mediaId": "9428c177111fcaea066fce717cdb74b9779466e7", + "cropId": "0_18_3379_4225", + "source": "The Guardian. Food styling: Katie Giovanni.", + "caption": "YOTAM_main_cauliflower_no_cream.tif\nYotam Ottolenghi\nCauliflower recipes for Weekend maagzine", + "mediaApiUri": "https://api.media.gutools.co.uk/images/9428c177111fcaea066fce717cdb74b9779466e7", + "width": 1600, + "height": 2000, + "photographer": "Johanna Parkin", + "imageType": "Photograph", + "displayCredit": true + }, + "id": "c2c9118b7e7b4a4aae48f31d4704dbd1", + "ingredients": [ + { + "ingredientsList": [ + { + "amount": { + "min": 1, + "max": 1 + }, + "name": "cauliflower", + "optional": false, + "prefix": "large", + "suffix": "with its leaves intact", + "text": "1 large cauliflower with its leaves intact" + }, + { + "amount": { + "max": 150, + "min": 150 + }, + "name": "creme fraiche", + "optional": false, + "text": "150 g creme fraiche", + "unit": "g" + }, + { + "amount": { + "max": 1, + "min": 1 + }, + "name": "lemon juice", + "optional": false, + "text": "1 tbsp lemon juice", + "unit": "tbsp" + }, + { + "amount": { + "min": 70, + "max": 70 + }, + "name": "unsalted butter", + "optional": false, + "suffix": "softened to room temperature", + "text": "70 g unsalted butter, softened to room temperature", + "unit": "g" + }, + { + "amount": { + "max": 3, + "min": 3 + }, + "name": "olive oil", + "optional": false, + "text": "3 tbsp olive oil", + "unit": "tbsp" + }, + { + "amount": { + "min": null, + "max": null + }, + "name": "Coarse sea salt", + "optional": false, + "text": "Coarse sea salt" + } + ], + "recipeSection": "" + } + ], + "instructions": [ + { + "description": "Using a pair of scissors, lightly trim the leaves at the top of the cauliflower, so that about 5cm of the cauliflower’s head is exposed." + }, + { + "description": "Fill a pan large enough to fit the cauliflower in salty water. Bring to a boil and carefully lower in the cauliflower exposed head down: don’t worry if the base sticks out a little. Bring back to a boil, cook for six minutes, then transfer the cauliflower to a colander, exposed head down. Set aside for 10 minutes, to drain and cool." + }, + { + "description": "Heat the oven to 170C/335F/gas mark 3." + }, + { + "description": "Mix together the creme fraiche and lemon juice, and set aside in the fridge until required." + }, + { + "description": "Mix the butter with the oil." + }, + { + "description": "Put the cauliflower stem side down in a medium baking tray and spread the butter mix all over the white flower. Sprinkle over a teaspoon and a quarter of salt, and roast for an hour and a half to two hours, basting the cauliflower with the buttery juices five or six times during cooking. The cauliflower is done when it’s super-tender and a dark golden-brown, and the leaves are crisp and charred." + }, + { + "description": "Remove from the oven and serve with the lemony creme fraiche and a little extra salt for sprinkling on top alongside." + } + ], + "isAppReady": false, + "mealTypeIds": [ + "side" + ], + "serves": [ + { + "amount": { + "max": 4, + "min": 4 + }, + "text": "Serves four as a starter", + "unit": "people" + } + ], + "suitableForDietIds": [ + "meat-free", + "vegetarian", + "gluten-free", + "pescatarian" + ], + "techniquesUsedIds": [], + "timings": [], + "title": "Roasted whole cauliflower with creme fraiche", + "utensilsAndApplianceIds": [], + "byline": [], + "previewImage": { + "url": "https://i.guim.co.uk/img/media/9428c177111fcaea066fce717cdb74b9779466e7/0_18_3379_4225/master/3379.jpg?width=1600&dpr=1&s=none", + "mediaId": "9428c177111fcaea066fce717cdb74b9779466e7", + "cropId": "0_18_3379_4225", + "source": "The Guardian. Food styling: Katie Giovanni.", + "caption": "YOTAM_main_cauliflower_no_cream.tif\nYotam Ottolenghi\nCauliflower recipes for Weekend maagzine", + "mediaApiUri": "https://api.media.gutools.co.uk/images/9428c177111fcaea066fce717cdb74b9779466e7", + "width": 1600, + "height": 2000, + "photographer": "Johanna Parkin", + "imageType": "Photograph", + "displayCredit": true + } +} diff --git a/fronts-client/src/bundles/recipesBundle.ts b/fronts-client/src/bundles/recipesBundle.ts index 40a330f43dc..8ea6aeea143 100644 --- a/fronts-client/src/bundles/recipesBundle.ts +++ b/fronts-client/src/bundles/recipesBundle.ts @@ -1,5 +1,7 @@ import createAsyncResourceBundle from 'lib/createAsyncResourceBundle'; import { Recipe } from 'types/Recipe'; +import recipe1 from "./fixtures/recipe1.json" +import recipe2 from "./fixtures/recipe2.json" type RecipesState = Recipe[]; @@ -8,20 +10,6 @@ export const { actions, reducer, selectors } = indexById: true, // Add stub data in the absence of proper search data. initialData: [ - { - id: 'example-recipe', - featuredImage: { - url: 'https://media.guim.co.uk/7f96c515c4e320b8ded848f23ffdef8bd311fcad/245_1381_2750_2751/2000.jpg', - mediaId: '7f96c515c4e320b8ded848f23ffdef8bd311fcad', - cropId: '', - source: 'The Guardian. Food stylist: Loic Parisot.', - photographer: 'Robert Billington', - caption: - 'Felicity Cloake’s Thai green curry works with chicken, seafood, pork, beef or tofu.', - mediaApiUri: '', - width: 2000, - height: 2000, - }, - }, + recipe1, recipe2 ], }); diff --git a/fronts-client/src/components/feed/FeedItem.tsx b/fronts-client/src/components/feed/FeedItem.tsx index e7493539872..a3b9447d6e0 100644 --- a/fronts-client/src/components/feed/FeedItem.tsx +++ b/fronts-client/src/components/feed/FeedItem.tsx @@ -101,6 +101,7 @@ const VideoIconContainer = styled(CircularIconContainer)` `; interface FeedItemProps { + id: string; title: string; liveUrl: string; metaContent: JSX.Element; diff --git a/fronts-client/src/components/feed/RecipeFeedItem.tsx b/fronts-client/src/components/feed/RecipeFeedItem.tsx index e69de29bb2d..e9343ac09d2 100644 --- a/fronts-client/src/components/feed/RecipeFeedItem.tsx +++ b/fronts-client/src/components/feed/RecipeFeedItem.tsx @@ -0,0 +1,31 @@ +import {Recipe} from "../../types/Recipe"; +import {FeedItem} from "./FeedItem"; +import React from "react"; +import {dragOffsetX, dragOffsetY} from "../FrontsEdit/CollectionComponents/ArticleDrag"; + +interface ComponentProps { + recipe: Recipe +} + +export const RecipeFeedItem = ({ recipe }: ComponentProps) => { + const handleDragStart = (event: React.DragEvent, dragNode: HTMLDivElement) => { + event.dataTransfer.setData('capi', JSON.stringify(recipe)); + if (dragNode) { + event.dataTransfer.setDragImage( + dragNode, + dragOffsetX, + dragOffsetY + ); + } + }; + + return ( + + ) +} diff --git a/fronts-client/src/components/feed/RecipeSearchContainer.tsx b/fronts-client/src/components/feed/RecipeSearchContainer.tsx index b1fe335b594..2cee1653b5c 100644 --- a/fronts-client/src/components/feed/RecipeSearchContainer.tsx +++ b/fronts-client/src/components/feed/RecipeSearchContainer.tsx @@ -9,6 +9,7 @@ import { State } from 'types/State'; import { Recipe } from 'types/Recipe'; import { SearchResultsHeadingContainer } from './SearchResultsHeadingContainer'; import { SearchTitle } from './SearchTitle'; +import {RecipeFeedItem} from "./RecipeFeedItem"; const InputContainer = styled.div` margin-bottom: 10px; @@ -47,7 +48,7 @@ const FeastSearchContainerComponent = ({ - {recipes.map((recipe) => JSON.stringify(recipe))} + {recipes.map((recipe) => )} ); diff --git a/fronts-client/src/types/Recipe.ts b/fronts-client/src/types/Recipe.ts index 636f27e72b2..75562954715 100644 --- a/fronts-client/src/types/Recipe.ts +++ b/fronts-client/src/types/Recipe.ts @@ -16,6 +16,8 @@ export interface RecipeImage { // be useful to derive from a package. export interface Recipe { id: string; + title: string; + canonicalArticle: string; featuredImage: RecipeImage; // the latter is an old image format that appears in our test fixtures previewImage?: RecipeImage; }