diff --git a/packages/webapp/public/locales/en/animal.json b/packages/webapp/public/locales/en/animal.json index 3f812cb1e9..6f24df2682 100644 --- a/packages/webapp/public/locales/en/animal.json +++ b/packages/webapp/public/locales/en/animal.json @@ -1,22 +1,48 @@ { "BREED": { "ANGUS": "Angus", - "HEREFORD": "Hereford", "CHAROLAIS": "Charolais", - "YORKSHIRE_LARGE_WHITE": "Yorkshire Large White", - "LANDRACE": "Landrace", - "DUROC": "Duroc", - "CORNISH_CROSS": "Cornish Cross", - "ROSS_308": "Ross 308", "COBB_500": "Cobb 500", + "CORNISH_CROSS": "Cornish Cross", + "DUROC": "Duroc", + "HEREFORD": "Hereford", + "LANDRACE": "Landrace", "LEGHORN": "Leghorn", + "PLYMOUTH_ROCK": "Plymouth Rock", "RHODE_ISLAND_RED": "Rhode Island Red", - "PLYMOUTH_ROCK": "Plymouth Rock" + "ROSS_308": "Ross 308", + "YORKSHIRE_LARGE_WHITE": "Yorkshire Large White" + }, + "ORIGIN": { + "BORN_AT_FARM": "Born at the farm", + "BROUGHT_IN": "Brought in" + }, + "SEX": { + "MALE": "Male", + "FEMALE": "Female" + }, + "TAG_COLOR": { + "BLUE": "Blue", + "GREEN": "Green", + "ORANGE": "Orange", + "RED": "Red", + "WHITE": "White", + "YELLOW": "Yellow" + }, + "TAG_PLACEMENT": { + "LEFT_EAR": "Left ear", + "LEFT_LEG": "Left leg", + "RIGHT_EAR": "Right ear", + "RIGHT_LEG": "Right leg" + }, + "TAG_TYPE": { + "EAR_TAG": "Ear tag", + "LEG_BAND": "Leg band" }, "TYPE": { "CATTLE": "Cattle", - "PIGS": "Pigs", - "CHICKEN": "Chicken" + "CHICKEN": "Chicken", + "PIGS": "Pigs" }, "USE": { "MILK": "Milk", diff --git a/packages/webapp/public/locales/en/common.json b/packages/webapp/public/locales/en/common.json index 719c3da4fa..6994f8e753 100644 --- a/packages/webapp/public/locales/en/common.json +++ b/packages/webapp/public/locales/en/common.json @@ -23,6 +23,7 @@ "CREATE_A_TASK": "Create a task", "DATE": "Date", "DELETE": "Delete", + "DO_NOT_KNOW": "I don't know", "DO_NOT_SHOW": "Don’t show this message again.", "EDIT": "Edit", "EDIT_DATE": "Edit date", @@ -43,15 +44,18 @@ "NEEDS_PLAN": "Needs plan", "NEXT": "Next", "NO": "No", + "NON_ORGANIC": "Non-organic", "NONE": "none", "NOT_SURE": "Not sure", "NOTES": "Notes", "OK": "OK", "OPTIONAL": "(optional)", "OR": "or", + "ORGANIC": "Organic", "OTHER": "Other", "PAST": "Past", "PLANNED": "Planned", + "PRICE": "Price", "PROCEED": "Proceed", "QUANTITY": "Quantity", "REMOVE": "Remove", @@ -76,11 +80,13 @@ "THATS_FINE": "That’s fine", "TODAY": "Today", "TOTAL": "Total", + "TRANSITIONING": "Transitioning", "TYPE": "Type", "TYPES": "Types", "UPDATE": "Update", "UPLOAD": "Upload", "UPLOADING": "Uploading...", + "USE": "Use", "WORD_LIMIT_ERROR": "Only {{value}} characters can be displayed", "YEAR": "Year", "YES": "Yes", diff --git a/packages/webapp/public/locales/en/translation.json b/packages/webapp/public/locales/en/translation.json index 0e39084a34..4d22988204 100644 --- a/packages/webapp/public/locales/en/translation.json +++ b/packages/webapp/public/locales/en/translation.json @@ -4,8 +4,27 @@ "ANIMALS_TOTAL_other": "{{count}} animals total", "ANIMALS_UNSPECIFIED_one": "{{count}} unspecified", "ANIMALS_UNSPECIFIED_other": "{{count}} unspecified", + "GENERAL_DETAILS": "General details", + "ORIGIN": "Origin", + "OTHER_DETAILS": "Other details", "OUT_OF_COUNT_one": "{{animalNumber}} out of {{count}}", "OUT_OF_COUNT_other": "{{animalNumber}} out of {{count}}", + "PLACEHOLDER": { + "BATCH_NAME": "Type in the batch name", + "DAM": "Type in a dam", + "MERCHANT": "Type in a merchant", + "NAME": "Type in a name", + "ORGANIC_STATUS": "What's the organic status?", + "OTHER_DETAILS": "Enter a description", + "PRICE": "How much did it cost?", + "SIRE": "Type in a sire", + "TAG_COLOUR": "What colour is the tag?", + "TAG_NUMBER": "Type in the tag number", + "TAG_PLACEMENT": "Where is the tag located?", + "TAG_PLACEMENT_INFO": "Tell us where the tag is", + "TAG_TYPE": "What is the tag type?", + "TAG_TYPE_INFO": "Please describe your tag type" + }, "REMOVE_CONFIRM": "Do you really want to remove?", "SELECT_SEXES": "Select sexes", "SEX_DETAIL": "Sex detail", @@ -23,7 +42,9 @@ "BATCH_SUMMARY_COUNT_other": "{{count}} batches", "HERE_IS_SUMMARY": "Here is a summary of your added animals:", "MAIN": "You successfully added {{animalCount}} {{and}} {{batchCount}} to your inventory." - } + }, + "UNIQUE_DETAILS": "Unique details", + "USED_FOR_REPRODUCTION": "Used for reproduction?" }, "ADD_FARM": { "ADDRESS_IS_REQUIRED": "Address is required", @@ -193,6 +214,24 @@ "ANIMAL_LOCATIONS": "Location", "ANIMAL_SEXES": "Sex", "ANIMAL_TYPE": "Type", + "ATTRIBUTE": { + "ANIMAL_IMAGE": "Animal image", + "BATCH_IMAGE": "Batch image", + "BATCH_NAME": "Batch name", + "DAM": "Dam", + "DATE_OF_BIRTH": "Date of birth", + "MERCHANT": "Merchant", + "ORGANIC_STATUS": "Organic status", + "OTHER_DETAILS_ANIMAL": "Other animal details", + "OTHER_DETAILS_BATCH": "Batch details", + "SIRE": "Sire", + "TAG_COLOUR": "Tag colour", + "TAG_NUMBER": "Tag number", + "TAG_PLACEMENT": "Tag placement", + "TAG_PLACEMENT_INFO": "Specify tag placement", + "TAG_TYPE": "Tag type", + "WEANING_DATE": "Weaning date" + }, "BATCH": "Batch", "FILTER": { "BATCHES": "Batches", @@ -1927,6 +1966,13 @@ "MAYBE_LATER": "Maybe it’ll turnip later.", "UNKNOWN_RECORD": "Unknown record" }, + "UPLOADER": { + "CHANGE_IMAGE": "Change Image", + "CLICK_TO_UPLOAD": "Click to upload", + "DRAG_DROP": "or drag and drop", + "REMOVE_IMAGE": "Remove Image", + "UPLOAD_IMAGE": "Upload Image" + }, "WAGE": { "ERROR": "Wage must be a valid, non-negative decimal number", "HOURLY_WAGE": "Hourly Wage", diff --git a/packages/webapp/public/locales/es/animal.json b/packages/webapp/public/locales/es/animal.json index 1913f7e32c..473da9d6be 100644 --- a/packages/webapp/public/locales/es/animal.json +++ b/packages/webapp/public/locales/es/animal.json @@ -1,22 +1,48 @@ { "BREED": { "ANGUS": "MISSING", - "HEREFORD": "MISSING", "CHAROLAIS": "MISSING", - "YORKSHIRE_LARGE_WHITE": "MISSING", - "LANDRACE": "MISSING", - "DUROC": "MISSING", - "CORNISH_CROSS": "MISSING", - "ROSS_308": "MISSING", "COBB_500": "MISSING", + "CORNISH_CROSS": "MISSING", + "DUROC": "MISSING", + "HEREFORD": "MISSING", + "LANDRACE": "MISSING", "LEGHORN": "MISSING", + "PLYMOUTH_ROCK": "MISSING", "RHODE_ISLAND_RED": "MISSING", - "PLYMOUTH_ROCK": "MISSING" + "ROSS_308": "MISSING", + "YORKSHIRE_LARGE_WHITE": "MISSING" + }, + "ORIGIN": { + "BORN_AT_FARM": "MISSING", + "BROUGHT_IN": "MISSING" + }, + "SEX": { + "MALE": "MISSING", + "FEMALE": "MISSING" + }, + "TAG_COLOR": { + "BLUE": "MISSING", + "GREEN": "MISSING", + "ORANGE": "MISSING", + "RED": "MISSING", + "WHITE": "MISSING", + "YELLOW": "MISSING" + }, + "TAG_PLACEMENT": { + "LEFT_EAR": "MISSING", + "LEFT_LEG": "MISSING", + "RIGHT_EAR": "MISSING", + "RIGHT_LEG": "MISSING" + }, + "TAG_TYPE": { + "EAR_TAG": "MISSING", + "LEG_BAND": "MISSING" }, "TYPE": { "CATTLE": "MISSING", - "PIGS": "MISSING", - "CHICKEN": "MISSING" + "CHICKEN": "MISSING", + "PIGS": "MISSING" }, "USE": { "MILK": "MISSING", diff --git a/packages/webapp/public/locales/es/common.json b/packages/webapp/public/locales/es/common.json index 859004972e..c5847bc64e 100644 --- a/packages/webapp/public/locales/es/common.json +++ b/packages/webapp/public/locales/es/common.json @@ -23,6 +23,7 @@ "CREATE_A_TASK": "MISSING", "DATE": "Fecha", "DELETE": "Borrar", + "DO_NOT_KNOW": "MISSING", "DO_NOT_SHOW": "No vuelva a mostrar este mensaje.", "EDIT": "Editar", "EDIT_DATE": "Editar fecha", @@ -43,15 +44,18 @@ "NEEDS_PLAN": "Necesita un plan", "NEXT": "Próximo", "NO": "No", + "NON_ORGANIC": "No orgánico", "NONE": "MISSING", "NOT_SURE": "No estoy seguro/a", "NOTES": "Notas", "OK": "Está bien", "OPTIONAL": "(opcional)", "OR": "MISSING", + "ORGANIC": "Orgánico", "OTHER": "Otro", "PAST": "Pasado", "PLANNED": "Planificado", + "PRICE": "MISSING", "PROCEED": "Proceder", "QUANTITY": "Cantidad", "REMOVE": "MISSING", @@ -76,11 +80,13 @@ "THATS_FINE": "Está bien", "TODAY": "Hoy", "TOTAL": "Total", + "TRANSITIONING": "En transición", "TYPE": "Tipo", "TYPES": "MISSING", "UPDATE": "Actualizar", "UPLOAD": "Subir", "UPLOADING": "Subiendo", + "USE": "MISSING", "WORD_LIMIT_ERROR": "Solo se pueden mostrar {{value}} caracteres", "YEAR": "Año", "YES": "Sí", diff --git a/packages/webapp/public/locales/es/translation.json b/packages/webapp/public/locales/es/translation.json index beb19b12cb..4fa09e1e1d 100644 --- a/packages/webapp/public/locales/es/translation.json +++ b/packages/webapp/public/locales/es/translation.json @@ -6,9 +6,28 @@ "ANIMALS_UNSPECIFIED_one": "MISSING", "ANIMALS_UNSPECIFIED_many": "MISSING", "ANIMALS_UNSPECIFIED_other": "MISSING", + "GENERAL_DETAILS": "MISSING", + "ORIGIN": "MISSING", + "OTHER_DETAILS": "MISSING", "OUT_OF_COUNT_one": "MISSING", "OUT_OF_COUNT_many": "MISSING", "OUT_OF_COUNT_other": "MISSING", + "PLACEHOLDER": { + "BATCH_NAME": "MISSING", + "DAM": "MISSING", + "MERCHANT": "MISSING", + "NAME": "MISSING", + "ORGANIC_STATUS": "MISSING", + "OTHER_DETAILS": "MISSING", + "PRICE": "MISSING", + "SIRE": "MISSING", + "TAG_COLOUR": "MISSING", + "TAG_NUMBER": "MISSING", + "TAG_PLACEMENT": "MISSING", + "TAG_PLACEMENT_INFO": "MISSING", + "TAG_TYPE": "MISSING", + "TAG_TYPE_INFO": "MISSING" + }, "REMOVE_CONFIRM": "MISSING", "SELECT_SEXES": "MISSING", "SEX_DETAIL": "MISSING", @@ -24,7 +43,9 @@ "ALL_DONE": "MISSING", "HERE_IS_SUMMARY": "MISSING", "MAIN": "MISSING" - } + }, + "UNIQUE_DETAILS": "MISSING", + "USED_FOR_REPRODUCTION": "MISSING" }, "ADD_FARM": { "ADDRESS_IS_REQUIRED": "MISSING", @@ -178,6 +199,24 @@ "ANIMAL_LOCATIONS": "MISSING", "ANIMAL_SEXES": "MISSING", "ANIMAL_TYPE": "MISSING", + "ATTRIBUTE": { + "ANIMAL_IMAGE": "MISSING", + "BATCH_IMAGE": "MISSING", + "BATCH_NAME": "MISSING", + "DAM": "MISSING", + "DATE_OF_BIRTH": "MISSING", + "MERCHANT": "MISSING", + "ORGANIC_STATUS": "MISSING", + "OTHER_DETAILS_ANIMAL": "MISSING", + "OTHER_DETAILS_BATCH": "MISSING", + "SIRE": "MISSING", + "TAG_COLOUR": "MISSING", + "TAG_NUMBER": "MISSING", + "TAG_PLACEMENT": "MISSING", + "TAG_PLACEMENT_INFO": "MISSING", + "TAG_TYPE": "MISSING", + "WEANING_DATE": "MISSING" + }, "BATCH": "MISSING", "FILTER": { "BATCHES": "MISSING", @@ -1725,6 +1764,13 @@ "MAYBE_LATER": "MISSING", "UNKNOWN_RECORD": "MISSING" }, + "UPLOADER": { + "CHANGE_IMAGE": "Cambiar imagen", + "CLICK_TO_UPLOAD": "Clickee para subir", + "DRAG_DROP": "o arrastre y suelte", + "REMOVE_IMAGE": "Eliminar imagen", + "UPLOAD_IMAGE": "Subir imagen" + }, "WAGE": { "ERROR": "MISSING", "HOURLY_WAGE": "MISSING", diff --git a/packages/webapp/public/locales/fr/animal.json b/packages/webapp/public/locales/fr/animal.json index 1913f7e32c..473da9d6be 100644 --- a/packages/webapp/public/locales/fr/animal.json +++ b/packages/webapp/public/locales/fr/animal.json @@ -1,22 +1,48 @@ { "BREED": { "ANGUS": "MISSING", - "HEREFORD": "MISSING", "CHAROLAIS": "MISSING", - "YORKSHIRE_LARGE_WHITE": "MISSING", - "LANDRACE": "MISSING", - "DUROC": "MISSING", - "CORNISH_CROSS": "MISSING", - "ROSS_308": "MISSING", "COBB_500": "MISSING", + "CORNISH_CROSS": "MISSING", + "DUROC": "MISSING", + "HEREFORD": "MISSING", + "LANDRACE": "MISSING", "LEGHORN": "MISSING", + "PLYMOUTH_ROCK": "MISSING", "RHODE_ISLAND_RED": "MISSING", - "PLYMOUTH_ROCK": "MISSING" + "ROSS_308": "MISSING", + "YORKSHIRE_LARGE_WHITE": "MISSING" + }, + "ORIGIN": { + "BORN_AT_FARM": "MISSING", + "BROUGHT_IN": "MISSING" + }, + "SEX": { + "MALE": "MISSING", + "FEMALE": "MISSING" + }, + "TAG_COLOR": { + "BLUE": "MISSING", + "GREEN": "MISSING", + "ORANGE": "MISSING", + "RED": "MISSING", + "WHITE": "MISSING", + "YELLOW": "MISSING" + }, + "TAG_PLACEMENT": { + "LEFT_EAR": "MISSING", + "LEFT_LEG": "MISSING", + "RIGHT_EAR": "MISSING", + "RIGHT_LEG": "MISSING" + }, + "TAG_TYPE": { + "EAR_TAG": "MISSING", + "LEG_BAND": "MISSING" }, "TYPE": { "CATTLE": "MISSING", - "PIGS": "MISSING", - "CHICKEN": "MISSING" + "CHICKEN": "MISSING", + "PIGS": "MISSING" }, "USE": { "MILK": "MISSING", diff --git a/packages/webapp/public/locales/fr/common.json b/packages/webapp/public/locales/fr/common.json index 7c13a22a46..15ecbcac7b 100644 --- a/packages/webapp/public/locales/fr/common.json +++ b/packages/webapp/public/locales/fr/common.json @@ -23,6 +23,7 @@ "CREATE_A_TASK": "MISSING", "DATE": "Date", "DELETE": "Effacer", + "DO_NOT_KNOW": "MISSING", "DO_NOT_SHOW": "Ne plus afficher ce message", "EDIT": "Modifier", "EDIT_DATE": "Modifier la Date", @@ -43,15 +44,18 @@ "NEEDS_PLAN": "Plan Requis", "NEXT": "Suivant", "NO": "Non", + "NON_ORGANIC": "Non-bio", "NONE": "MISSING", "NOT_SURE": "Incertain(e)", "NOTES": "Notes", "OK": "OK", "OPTIONAL": "(optionnel)", "OR": "MISSING", + "ORGANIC": "Biologique", "OTHER": "Autre", "PAST": "Passé", "PLANNED": "Planifié", + "PRICE": "MISSING", "PROCEED": "Continuer", "QUANTITY": "Quantité", "REMOVE": "MISSING", @@ -76,11 +80,13 @@ "THATS_FINE": "C'est bien", "TODAY": "Aujourd'hui", "TOTAL": "Total", + "TRANSITIONING": "Transition", "TYPE": "Type", "TYPES": "MISSING", "UPDATE": "Mettre à Jour", "UPLOAD": "Télécharger", "UPLOADING": "Téléchargement...", + "USE": "MISSING", "WORD_LIMIT_ERROR": "Limité à {{value}} mots", "YEAR": "Année", "YES": "Oui", diff --git a/packages/webapp/public/locales/fr/translation.json b/packages/webapp/public/locales/fr/translation.json index d515692197..ee808ff8ad 100644 --- a/packages/webapp/public/locales/fr/translation.json +++ b/packages/webapp/public/locales/fr/translation.json @@ -6,9 +6,28 @@ "ANIMALS_UNSPECIFIED_one": "MISSING", "ANIMALS_UNSPECIFIED_many": "MISSING", "ANIMALS_UNSPECIFIED_other": "MISSING", + "GENERAL_DETAILS": "MISSING", + "ORIGIN": "MISSING", + "OTHER_DETAILS": "MISSING", "OUT_OF_COUNT_one": "MISSING", "OUT_OF_COUNT_many": "MISSING", "OUT_OF_COUNT_other": "MISSING", + "PLACEHOLDER": { + "BATCH_NAME": "MISSING", + "DAM": "MISSING", + "MERCHANT": "MISSING", + "NAME": "MISSING", + "ORGANIC_STATUS": "MISSING", + "OTHER_DETAILS": "MISSING", + "PRICE": "MISSING", + "SIRE": "MISSING", + "TAG_COLOUR": "MISSING", + "TAG_NUMBER": "MISSING", + "TAG_PLACEMENT": "MISSING", + "TAG_PLACEMENT_INFO": "MISSING", + "TAG_TYPE": "MISSING", + "TAG_TYPE_INFO": "MISSING" + }, "REMOVE_CONFIRM": "MISSING", "SELECT_SEXES": "MISSING", "SEX_DETAIL": "MISSING", @@ -28,7 +47,9 @@ "BATCH_SUMMARY_COUNT_other": "MISSING", "HERE_IS_SUMMARY": "MISSING", "MAIN": "MISSING" - } + }, + "UNIQUE_DETAILS": "MISSING", + "USED_FOR_REPRODUCTION": "MISSING" }, "ADD_FARM": { "ADDRESS_IS_REQUIRED": "Une adresse est requise", @@ -198,6 +219,24 @@ "ANIMAL_LOCATIONS": "MISSING", "ANIMAL_SEXES": "MISSING", "ANIMAL_TYPE": "MISSING", + "ATTRIBUTE": { + "ANIMAL_IMAGE": "MISSING", + "BATCH_IMAGE": "MISSING", + "BATCH_NAME": "MISSING", + "DAM": "MISSING", + "DATE_OF_BIRTH": "MISSING", + "MERCHANT": "MISSING", + "ORGANIC_STATUS": "MISSING", + "OTHER_DETAILS_ANIMAL": "MISSING", + "OTHER_DETAILS_BATCH": "MISSING", + "SIRE": "MISSING", + "TAG_COLOUR": "MISSING", + "TAG_NUMBER": "MISSING", + "TAG_PLACEMENT": "MISSING", + "TAG_PLACEMENT_INFO": "MISSING", + "TAG_TYPE": "MISSING", + "WEANING_DATE": "MISSING" + }, "BATCH": "MISSING", "FILTER": { "BATCHES": "MISSING", @@ -1936,6 +1975,13 @@ "MAYBE_LATER": "Espérons le trouver plus tard.", "UNKNOWN_RECORD": "Enregistrement inconnu" }, + "UPLOADER": { + "CHANGE_IMAGE": "Changer image", + "CLICK_TO_UPLOAD": "Cliquer pour télécharger", + "DRAG_DROP": "ou glisser déposer", + "REMOVE_IMAGE": "Supprimer image", + "UPLOAD_IMAGE": "Ajouter une image" + }, "WAGE": { "ERROR": "Le salaire doit être un nombre décimal valide et non négatif", "HOURLY_WAGE": "Salaire horaire", diff --git a/packages/webapp/public/locales/pt/animal.json b/packages/webapp/public/locales/pt/animal.json index 1913f7e32c..473da9d6be 100644 --- a/packages/webapp/public/locales/pt/animal.json +++ b/packages/webapp/public/locales/pt/animal.json @@ -1,22 +1,48 @@ { "BREED": { "ANGUS": "MISSING", - "HEREFORD": "MISSING", "CHAROLAIS": "MISSING", - "YORKSHIRE_LARGE_WHITE": "MISSING", - "LANDRACE": "MISSING", - "DUROC": "MISSING", - "CORNISH_CROSS": "MISSING", - "ROSS_308": "MISSING", "COBB_500": "MISSING", + "CORNISH_CROSS": "MISSING", + "DUROC": "MISSING", + "HEREFORD": "MISSING", + "LANDRACE": "MISSING", "LEGHORN": "MISSING", + "PLYMOUTH_ROCK": "MISSING", "RHODE_ISLAND_RED": "MISSING", - "PLYMOUTH_ROCK": "MISSING" + "ROSS_308": "MISSING", + "YORKSHIRE_LARGE_WHITE": "MISSING" + }, + "ORIGIN": { + "BORN_AT_FARM": "MISSING", + "BROUGHT_IN": "MISSING" + }, + "SEX": { + "MALE": "MISSING", + "FEMALE": "MISSING" + }, + "TAG_COLOR": { + "BLUE": "MISSING", + "GREEN": "MISSING", + "ORANGE": "MISSING", + "RED": "MISSING", + "WHITE": "MISSING", + "YELLOW": "MISSING" + }, + "TAG_PLACEMENT": { + "LEFT_EAR": "MISSING", + "LEFT_LEG": "MISSING", + "RIGHT_EAR": "MISSING", + "RIGHT_LEG": "MISSING" + }, + "TAG_TYPE": { + "EAR_TAG": "MISSING", + "LEG_BAND": "MISSING" }, "TYPE": { "CATTLE": "MISSING", - "PIGS": "MISSING", - "CHICKEN": "MISSING" + "CHICKEN": "MISSING", + "PIGS": "MISSING" }, "USE": { "MILK": "MISSING", diff --git a/packages/webapp/public/locales/pt/common.json b/packages/webapp/public/locales/pt/common.json index 3e38da66f5..b94eedbacc 100644 --- a/packages/webapp/public/locales/pt/common.json +++ b/packages/webapp/public/locales/pt/common.json @@ -23,6 +23,7 @@ "CREATE_A_TASK": "MISSING", "DATE": "Data", "DELETE": "Excluir", + "DO_NOT_KNOW": "MISSING", "DO_NOT_SHOW": "Não mostrar esta mensagem novamente", "EDIT": "Editar", "EDIT_DATE": "Editar data", @@ -43,15 +44,18 @@ "NEEDS_PLAN": "É necessário um plano", "NEXT": "Próximo", "NO": "Não", + "NON_ORGANIC": "Não orgânico", "NONE": "MISSING", "NOT_SURE": "Não tem certeza", "NOTES": "Notas", "OK": "Ok", "OPTIONAL": "(Opcional)", "OR": "MISSING", + "ORGANIC": "Orgânico", "OTHER": "Outro", "PAST": "Passado", "PLANNED": "Planejado", + "PRICE": "MISSING", "PROCEED": "Continuar", "QUANTITY": "Quantidade", "REMOVE": "MISSING", @@ -76,11 +80,13 @@ "THATS_FINE": "Está bom", "TODAY": "Hoje", "TOTAL": "Total", + "TRANSITIONING": "Em transição", "TYPE": "Tipo", "TYPES": "MISSING", "UPDATE": "Atualizar", "UPLOAD": "Carregar", "UPLOADING": "Carregando", + "USE": "MISSING", "WORD_LIMIT_ERROR": "Somente {{value}} caractéres podem ser exibidos", "YEAR": "Ano", "YES": "Sim", diff --git a/packages/webapp/public/locales/pt/translation.json b/packages/webapp/public/locales/pt/translation.json index 450f6ad488..999a7238c7 100644 --- a/packages/webapp/public/locales/pt/translation.json +++ b/packages/webapp/public/locales/pt/translation.json @@ -6,9 +6,28 @@ "ANIMALS_UNSPECIFIED_one": "MISSING", "ANIMALS_UNSPECIFIED_many": "MISSING", "ANIMALS_UNSPECIFIED_other": "MISSING", + "GENERAL_DETAILS": "MISSING", + "ORIGIN": "MISSING", + "OTHER_DETAILS": "MISSING", "OUT_OF_COUNT_one": "MISSING", "OUT_OF_COUNT_many": "MISSING", "OUT_OF_COUNT_other": "MISSING", + "PLACEHOLDER": { + "BATCH_NAME": "MISSING", + "DAM": "MISSING", + "MERCHANT": "MISSING", + "NAME": "MISSING", + "ORGANIC_STATUS": "MISSING", + "OTHER_DETAILS": "MISSING", + "PRICE": "MISSING", + "SIRE": "MISSING", + "TAG_COLOUR": "MISSING", + "TAG_NUMBER": "MISSING", + "TAG_PLACEMENT": "MISSING", + "TAG_PLACEMENT_INFO": "MISSING", + "TAG_TYPE": "MISSING", + "TAG_TYPE_INFO": "MISSING" + }, "REMOVE_CONFIRM": "MISSING", "SELECT_SEXES": "MISSING", "SEX_DETAIL": "MISSING", @@ -28,7 +47,9 @@ "BATCH_SUMMARY_COUNT_other": "MISSING", "HERE_IS_SUMMARY": "MISSING", "MAIN": "MISSING" - } + }, + "UNIQUE_DETAILS": "MISSING", + "USED_FOR_REPRODUCTION": "MISSING" }, "ADD_FARM": { "ADDRESS_IS_REQUIRED": "É necessário informar um endereço", @@ -198,6 +219,24 @@ "ANIMAL_LOCATIONS": "MISSING", "ANIMAL_SEXES": "MISSING", "ANIMAL_TYPE": "MISSING", + "ATTRIBUTE": { + "ANIMAL_IMAGE": "MISSING", + "BATCH_IMAGE": "MISSING", + "BATCH_NAME": "MISSING", + "DAM": "MISSING", + "DATE_OF_BIRTH": "MISSING", + "MERCHANT": "MISSING", + "ORGANIC_STATUS": "MISSING", + "OTHER_DETAILS_ANIMAL": "MISSING", + "OTHER_DETAILS_BATCH": "MISSING", + "SIRE": "MISSING", + "TAG_COLOUR": "MISSING", + "TAG_NUMBER": "MISSING", + "TAG_PLACEMENT": "MISSING", + "TAG_PLACEMENT_INFO": "MISSING", + "TAG_TYPE": "MISSING", + "WEANING_DATE": "MISSING" + }, "BATCH": "MISSING", "FILTER": { "BATCHES": "MISSING", @@ -1935,6 +1974,13 @@ "MAYBE_LATER": "Talvez apareça mais tarde.", "UNKNOWN_RECORD": "Registro desconhecido" }, + "UPLOADER": { + "CHANGE_IMAGE": "Alterar imagem", + "CLICK_TO_UPLOAD": "Clique para enviar", + "DRAG_DROP": "ou arraste e solte", + "REMOVE_IMAGE": "Remover imagem", + "UPLOAD_IMAGE": "Enviar imagem" + }, "WAGE": { "ERROR": "Salário/vencimento precisa ser um número decimal válido não-negativo", "HOURLY_WAGE": "Salário por hora", diff --git a/packages/webapp/src/assets/colors.scss b/packages/webapp/src/assets/colors.scss index 89520e0934..e5f64b78f9 100644 --- a/packages/webapp/src/assets/colors.scss +++ b/packages/webapp/src/assets/colors.scss @@ -124,4 +124,6 @@ --Colors-Accent---singles-Brown-dark: #633700; --Colors-Accent---singles-Purple-light: #f4e8ff; --Colors-Accent---singles-Purple-full: #8f26f0; + + --Form-focus: #89d1c7; } diff --git a/packages/webapp/src/components/Animals/AddAnimalsDetails/General.tsx b/packages/webapp/src/components/Animals/AddAnimalsDetails/General.tsx new file mode 100644 index 0000000000..974dac7d9a --- /dev/null +++ b/packages/webapp/src/components/Animals/AddAnimalsDetails/General.tsx @@ -0,0 +1,146 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { useMemo } from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; +import Input, { getInputErrors } from '../../Form/Input'; +import RadioGroup from '../../Form/RadioGroup'; +import ReactSelect from '../../Form/ReactSelect'; +import InputBaseLabel from '../../Form/InputBase/InputBaseLabel'; +import { AnimalOrBatchKeys } from '../../../containers/Animals/types'; +import { DetailsFields, type Option, type CommonDetailsProps } from './type'; +import styles from './styles.module.scss'; + +export type GeneralDetailsProps = CommonDetailsProps & { + typeOptions: Option[DetailsFields.TYPE][]; + breedOptions: Option[DetailsFields.BREED][]; + sexOptions: Option[DetailsFields.SEX][]; + useOptions: Option[DetailsFields.USE][]; + animalOrBatch: AnimalOrBatchKeys; + isMaleSelected?: boolean; +}; + +const GeneralDetails = ({ + t, + typeOptions, + breedOptions, + sexOptions, + useOptions, + animalOrBatch, + isMaleSelected, +}: GeneralDetailsProps) => { + const { + control, + register, + trigger, + formState: { errors }, + } = useFormContext(); + + const sexInputs = useMemo(() => { + if (animalOrBatch === AnimalOrBatchKeys.ANIMAL) { + return ( + <> +
+ + {/* @ts-ignore */} + +
+ {isMaleSelected && ( +
+ + {/* @ts-ignore */} + +
+ )} + + ); + } + + return 'TODO: LF-4159'; + }, [animalOrBatch, t, isMaleSelected, sexOptions, control]); + + return ( +
+ {animalOrBatch === AnimalOrBatchKeys.BATCH && ( + <> + {/* @ts-ignore */} + + + )} + ( + + )} + /> + ( + + )} + /> + {sexInputs} + ( + + )} + /> +
+ ); +}; + +export default GeneralDetails; diff --git a/packages/webapp/src/components/Animals/AddAnimalsDetails/Origin.tsx b/packages/webapp/src/components/Animals/AddAnimalsDetails/Origin.tsx new file mode 100644 index 0000000000..3fb8ebb98e --- /dev/null +++ b/packages/webapp/src/components/Animals/AddAnimalsDetails/Origin.tsx @@ -0,0 +1,123 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { useMemo } from 'react'; +import { useFormContext } from 'react-hook-form'; +import Input, { getInputErrors } from '../../Form/Input'; +import RadioGroup from '../../Form/RadioGroup'; +import { DetailsFields, type Option, type CommonDetailsProps } from './type'; +import { AnimalOrigins } from '../../../containers/Animals/types'; +import styles from './styles.module.scss'; + +export type OriginProps = CommonDetailsProps & { + currency: string; + originOptions: Option[DetailsFields.ORIGIN][]; + origin?: AnimalOrigins; +}; + +const Origin = ({ t, currency, originOptions, origin }: OriginProps) => { + const { + control, + register, + trigger, + formState: { errors }, + } = useFormContext(); + + const fields = useMemo(() => { + return origin === AnimalOrigins.BROUGHT_IN ? ( + <> + {/* @ts-ignore */} + + {/* @ts-ignore */} + + {/* @ts-ignore */} + + + ) : ( + <> + {/* @ts-ignore */} + + {/* @ts-ignore */} + + + ); + }, [origin, Object.entries(errors)]); + + return ( +
+
+ {/* @ts-ignore */} + +
+ {origin && fields} +
+ ); +}; + +export default Origin; diff --git a/packages/webapp/src/components/Animals/AddAnimalsDetails/Other.tsx b/packages/webapp/src/components/Animals/AddAnimalsDetails/Other.tsx new file mode 100644 index 0000000000..7094936216 --- /dev/null +++ b/packages/webapp/src/components/Animals/AddAnimalsDetails/Other.tsx @@ -0,0 +1,94 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { Controller, useController, useFormContext } from 'react-hook-form'; +import ReactSelect from '../../Form/ReactSelect'; +import Input from '../../Form/Input'; +import InputAutoSize from '../../Form/InputAutoSize'; +import ImagePicker from '../../ImagePicker'; +import { AnimalOrBatchKeys } from '../../../containers/Animals/types'; +import styles from './styles.module.scss'; +import { DetailsFields, type Option, type CommonDetailsProps } from './type'; + +export type OtherDetailsProps = CommonDetailsProps & { + organicStatusOptions: Option[DetailsFields.ORGANIC_STATUS][]; + animalOrBatch: AnimalOrBatchKeys; +}; + +const OtherDetails = ({ t, organicStatusOptions, animalOrBatch }: OtherDetailsProps) => { + const { + control, + resetField, + register, + formState: { errors }, + } = useFormContext(); + + const { field } = useController({ control, name: DetailsFields.ANIMAL_IMAGE }); + + const handleSelectImage = (imageFile: any) => { + field.onChange(imageFile); + }; + + const handleRemoveImage = () => { + resetField(DetailsFields.ANIMAL_IMAGE); + }; + + return ( +
+ {animalOrBatch === AnimalOrBatchKeys.ANIMAL && ( + <> + {/* @ts-ignore */} + + + )} + ( + + )} + /> + {/* @ts-ignore */} + + +
+ ); +}; + +export default OtherDetails; diff --git a/packages/webapp/src/components/Animals/AddAnimalsDetails/Unique.tsx b/packages/webapp/src/components/Animals/AddAnimalsDetails/Unique.tsx new file mode 100644 index 0000000000..fe09843019 --- /dev/null +++ b/packages/webapp/src/components/Animals/AddAnimalsDetails/Unique.tsx @@ -0,0 +1,155 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { Controller, useFormContext } from 'react-hook-form'; +import ReactSelect from '../../Form/ReactSelect'; +import Input, { getInputErrors } from '../../Form/Input'; +import { DetailsFields, type Option, type CommonDetailsProps } from './type'; +import styles from './styles.module.scss'; + +export type UniqueDetailsProps = CommonDetailsProps & { + tagTypeOptions: Option[DetailsFields.TAG_TYPE][]; + tagColorOptions: Option[DetailsFields.TAG_COLOR][]; + tagPlacementOptions: Option[DetailsFields.TAG_PLACEMENT][]; + shouldShowTagTypeInput?: boolean; + shouldShowTagPlacementInput?: boolean; +}; + +const UniqueDetails = ({ + t, + tagTypeOptions, + tagColorOptions, + tagPlacementOptions, + shouldShowTagTypeInput, + shouldShowTagPlacementInput, +}: UniqueDetailsProps) => { + const { + control, + register, + trigger, + formState: { errors }, + } = useFormContext(); + + return ( +
+ {/* @ts-ignore */} + + {/* @ts-ignore */} + + {/* @ts-ignore */} + + ( + + )} + /> + ( + + )} + /> + {shouldShowTagTypeInput && ( + <> + {/* @ts-ignore */} + + + )} + ( + + )} + /> + {shouldShowTagPlacementInput && ( + <> + {/* @ts-ignore */} + + + )} +
+ ); +}; + +export default UniqueDetails; diff --git a/packages/webapp/src/components/Animals/AddAnimalsDetails/index.tsx b/packages/webapp/src/components/Animals/AddAnimalsDetails/index.tsx new file mode 100644 index 0000000000..dfe5b2d6e3 --- /dev/null +++ b/packages/webapp/src/components/Animals/AddAnimalsDetails/index.tsx @@ -0,0 +1,107 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { useTranslation } from 'react-i18next'; +import clsx from 'clsx'; +import GeneralDetails, { type GeneralDetailsProps } from './General'; +import UniqueDetails, { type UniqueDetailsProps } from './Unique'; +import OtherDetails, { type OtherDetailsProps } from './Other'; +import Origin, { type OriginProps } from './Origin'; +import ExpandableItem from '../../Expandable/ExpandableItem'; +import useExpandable from '../../Expandable/useExpandableItem'; +import { AnimalOrBatchKeys } from '../../../containers/Animals/types'; +import styles from './styles.module.scss'; + +enum sectionKeys { + GENERAL, + ORIGIN, + UNIQUE, + OTHER, +} + +export type AnimalDetailsProps = { + generalDetailProps: Omit; + uniqueDetailsProps: Omit; + otherDetailsProps: Omit; + originProps: Omit; +}; + +const AnimalDetails = ({ + generalDetailProps, + uniqueDetailsProps, + otherDetailsProps, + originProps, +}: AnimalDetailsProps) => { + const { expandedIds, toggleExpanded } = useExpandable({ isSingleExpandable: true }); + const { t } = useTranslation(['translation', 'common', 'animal']); + const commonProps = { t }; + + const sections = [ + { + key: sectionKeys.GENERAL, + title: t('ADD_ANIMAL.GENERAL_DETAILS'), + content: ( + + ), + }, + { + key: sectionKeys.UNIQUE, + title: t('ADD_ANIMAL.UNIQUE_DETAILS'), + content: , + }, + { + key: sectionKeys.OTHER, + title: t('ADD_ANIMAL.OTHER_DETAILS'), + content: ( + + ), + }, + { + key: sectionKeys.ORIGIN, + title: t('ADD_ANIMAL.ORIGIN'), + content: , + }, + ]; + + return ( +
+ {sections.map(({ key, title, content }) => { + const isExpanded = expandedIds.includes(key); + + return ( +
+ toggleExpanded(key)} + mainContent={title} + expandedContent={
{content}
} + /> +
+ ); + })} +
+ ); +}; + +export default AnimalDetails; diff --git a/packages/webapp/src/components/Animals/AddAnimalsDetails/styles.module.scss b/packages/webapp/src/components/Animals/AddAnimalsDetails/styles.module.scss new file mode 100644 index 0000000000..51983aa1ae --- /dev/null +++ b/packages/webapp/src/components/Animals/AddAnimalsDetails/styles.module.scss @@ -0,0 +1,37 @@ +/* +* Copyright 2024 LiteFarm.org +* This file is part of LiteFarm. +* +* LiteFarm is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* LiteFarm is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details, see . +*/ + +.section { + padding: 16px; + background: var(--White); + border-radius: 4px; + border: 1px solid var(--Colors-Neutral-Neutral-100); +} + +.expanded { + border: 1px solid var(--Form-focus); + box-shadow: 0px 0px 4px 0px var(--Colors-Neutral-Neutral-200); +} + +.expandedContentWrapper { + margin-top: 16px; +} + +.detailsWrapper, +.sectionWrapper { + display: flex; + flex-direction: column; + gap: 16px; +} diff --git a/packages/webapp/src/components/Animals/AddAnimalsDetails/type.ts b/packages/webapp/src/components/Animals/AddAnimalsDetails/type.ts new file mode 100644 index 0000000000..09a9e0b3d6 --- /dev/null +++ b/packages/webapp/src/components/Animals/AddAnimalsDetails/type.ts @@ -0,0 +1,99 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { UseFormReturn } from 'react-hook-form'; +import { TFunction } from 'react-i18next'; + +export type ReactSelectOption = { + label: string; + value: T; +}; + +export enum DetailsFields { + // GENERAL + NAME = 'name', + TYPE = 'type', + BREED = 'breed', + SEX = 'sex', + USED_FOR_REPRODUCTION = 'USED_FOR_REPRODUCTION', + USE = 'use', + + // UNIQUE + DATE_OF_BIRTH = 'birth_date', + TAG_NUMBER = 'identifier', + TAG_COLOR = 'identifier_color_id', + TAG_TYPE = 'identifier_type', + TAG_TYPE_INFO = 'identifier_type_info', + TAG_PLACEMENT = 'identifier_placement_id', + TAG_PLACEMENT_INFO = 'identifier_placement_info', + + // OTHER + WEANING_DATE = 'weaning_date', + ORGANIC_STATUS = 'organic_status', + OTHER_DETAILS = 'notes', + ANIMAL_IMAGE = 'image_file', + + // ORIGIN + ORIGIN = 'origin_id', + DAM = 'dam', + SIRE = 'sire', + BROUGHT_IN_DATE = 'brought_in_date', + MERCHANT = 'merchant', + PRICE = 'price', +} + +export type Option = { + [DetailsFields.TYPE]: ReactSelectOption; // TODO: LF-4159 + [DetailsFields.BREED]: ReactSelectOption; // TODO: LF-4159 + [DetailsFields.USE]: ReactSelectOption; // TODO: LF-4159 + [DetailsFields.TAG_COLOR]: ReactSelectOption; + [DetailsFields.TAG_TYPE]: ReactSelectOption; + [DetailsFields.TAG_PLACEMENT]: ReactSelectOption; + [DetailsFields.ORGANIC_STATUS]: ReactSelectOption; + [DetailsFields.SEX]: ReactSelectOption; + [DetailsFields.ORIGIN]: ReactSelectOption; +}; + +export type FormValues = { + [DetailsFields.NAME]?: string; + [DetailsFields.TYPE]: Option[DetailsFields.TYPE]; + [DetailsFields.BREED]?: Option[DetailsFields.BREED]; + [DetailsFields.SEX]?: number; + [DetailsFields.USED_FOR_REPRODUCTION]?: boolean; + [DetailsFields.USE]?: Option[DetailsFields.USE][]; + [DetailsFields.DATE_OF_BIRTH]?: string; + [DetailsFields.TAG_NUMBER]?: string; + [DetailsFields.TAG_COLOR]?: Option[DetailsFields.TAG_COLOR]; + [DetailsFields.TAG_TYPE]?: Option[DetailsFields.TAG_TYPE]; + [DetailsFields.TAG_TYPE_INFO]?: string; + [DetailsFields.TAG_PLACEMENT]?: Option[DetailsFields.TAG_PLACEMENT] | null; + [DetailsFields.TAG_PLACEMENT_INFO]?: string; + [DetailsFields.WEANING_DATE]?: string; + [DetailsFields.ORGANIC_STATUS]?: Option[DetailsFields.TAG_TYPE]; + [DetailsFields.OTHER_DETAILS]?: string; + [DetailsFields.ANIMAL_IMAGE]?: any; + [DetailsFields.ORIGIN]?: number; + [DetailsFields.DAM]?: string; + [DetailsFields.SIRE]?: string; + [DetailsFields.BROUGHT_IN_DATE]?: string; + [DetailsFields.MERCHANT]?: string; + [DetailsFields.PRICE]?: number; +}; + +export interface FormMethods extends UseFormReturn {} + +export type CommonDetailsProps = { + t: TFunction; +}; diff --git a/packages/webapp/src/components/Form/FilePickerWrapper/index.tsx b/packages/webapp/src/components/Form/FilePickerWrapper/index.tsx index 0a4bf6b449..e727150a60 100644 --- a/packages/webapp/src/components/Form/FilePickerWrapper/index.tsx +++ b/packages/webapp/src/components/Form/FilePickerWrapper/index.tsx @@ -53,5 +53,5 @@ PureFilePickerWrapper.propTypes = { style: PropTypes.object, onChange: PropTypes.func, children: PropTypes.node, - className: PropTypes.object, + className: PropTypes.string, }; diff --git a/packages/webapp/src/components/Form/Input/index.jsx b/packages/webapp/src/components/Form/Input/index.jsx index 35e6bdce5e..e6e89e5b96 100644 --- a/packages/webapp/src/components/Form/Input/index.jsx +++ b/packages/webapp/src/components/Form/Input/index.jsx @@ -48,6 +48,7 @@ const Input = ({ currency, stepper = false, className = '', + trigger, ...props }) => { const { t } = useTranslation(['translation', 'common']); @@ -71,6 +72,8 @@ const Input = ({ input.current.value = ''; onChange?.({ target: input.current }); hookFormRegister?.onChange({ target: input.current }); + // Manually trigger validation against the new value '' + trigger?.(name); setShowError(false); }; @@ -277,6 +280,7 @@ Input.propTypes = { min: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), placeholder: PropTypes.string, className: PropTypes.string, + trigger: PropTypes.func, }; export default Input; diff --git a/packages/webapp/src/components/ImagePicker/index.tsx b/packages/webapp/src/components/ImagePicker/index.tsx new file mode 100644 index 0000000000..6b2dc1c79e --- /dev/null +++ b/packages/webapp/src/components/ImagePicker/index.tsx @@ -0,0 +1,129 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { ChangeEvent, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { AddLink } from '../Typography'; +import PureFilePickerWrapper from '../Form/FilePickerWrapper'; +import TextButton from '../Form/Button/TextButton'; +import InputBaseLabel from '../Form/InputBase/InputBaseLabel'; +import { ReactComponent as CameraIcon } from '../../assets/images/farm-profile/camera.svg'; +import { ReactComponent as TrashIcon } from '../../assets/images/farm-profile/trash.svg'; +import { ReactComponent as EditIcon } from '../../assets/images/farm-profile/edit.svg'; +import styles from './styles.module.scss'; + +export type ImagePickerProps = { + onSelectImage: (file: File) => void; + onRemoveImage: () => void; + label?: string; + optional?: boolean; + defaultUrl?: string; +}; + +export default function ImagePicker({ + onRemoveImage, + onSelectImage, + defaultUrl = '', + label, + optional = true, // false is not yet supported +}: ImagePickerProps) { + const [previewUrl, setPreviewUrl] = useState(defaultUrl); + const dropContainerRef = useRef(null); + const { t } = useTranslation(); + + const removeImage = () => { + onRemoveImage(); + setPreviewUrl(''); + }; + + const showImage = (file: File) => { + const url = URL.createObjectURL(file); + setPreviewUrl(url); + onSelectImage(file); + }; + + const handleFileInputChange = (e: ChangeEvent) => { + if (!e.target.files) return; + const file = e.target.files[0]; + showImage(file); + }; + + const handleDragEvent = (e: React.DragEvent) => { + e.preventDefault(); + if (e.type === 'dragover') return; + + if (e.type === 'dragenter' || e.type === 'dragleave') { + dropContainerRef.current?.classList.toggle(styles.dropContainerActive); + } else if (e.type === 'drop') { + const file = e.dataTransfer?.files[0]; + if (file) showImage(file); + } + }; + + useEffect(() => { + return () => URL.revokeObjectURL(previewUrl); + }, [previewUrl]); + + return ( +
+ {label && } + {previewUrl ? ( +
+ image preview +
+ + + + {t('UPLOADER.CHANGE_IMAGE')} + + + + + {t('UPLOADER.REMOVE_IMAGE')} + +
+
+ ) : ( + <> + + + {t('UPLOADER.UPLOAD_IMAGE')} + + +
+ +
+ + {t('UPLOADER.CLICK_TO_UPLOAD')} + + {t('UPLOADER.DRAG_DROP')} +
+
+ + )} +
+ ); +} diff --git a/packages/webapp/src/components/ImagePicker/styles.module.scss b/packages/webapp/src/components/ImagePicker/styles.module.scss new file mode 100644 index 0000000000..a3fcd228e8 --- /dev/null +++ b/packages/webapp/src/components/ImagePicker/styles.module.scss @@ -0,0 +1,89 @@ +/* +* Copyright 2024 LiteFarm.org +* This file is part of LiteFarm. +* +* LiteFarm is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* LiteFarm is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details, see . +*/ + +.imageContainer { + display: flex; + align-items: start; + + img { + max-width: 150px; + max-height: 75px; + object-fit: cover; + } +} + +.imageActions { + margin-left: 8px; + gap: 4px; + + button { + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + color: var(--teal700); + font-weight: 400; + } +} + +.filePickerBtn { + display: flex; + align-items: center; + gap: 8px; + font-weight: 700; + color: #634d00; + border: 1px solid var(--grey600); + border-radius: 4px; + padding: 12px 24px; +} + +.filePickerWrapper { + @media (min-width: 768px) { + display: none; + } +} + +.dropContainer { + display: none; + height: 145px; + background-color: var(--grey100); + border: 1px dashed var(--grey500); + border-radius: 4px; + + .cameraIcon { + width: 40px; + height: 40px; + path { + stroke: #abc7c1; + } + } + + .flexWrapper { + display: flex; + gap: 4px; + } + + @media (min-width: 768px) { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } +} + +.dropContainerActive { + background-color: var(--teal100); + border: 1px solid var(--teal500); +} diff --git a/packages/webapp/src/containers/Animals/types.ts b/packages/webapp/src/containers/Animals/types.ts index b5baa52270..fa922e9030 100644 --- a/packages/webapp/src/containers/Animals/types.ts +++ b/packages/webapp/src/containers/Animals/types.ts @@ -28,3 +28,13 @@ export enum AnimalOrBatchKeys { ANIMAL = 'ANIMAL', BATCH = 'BATCH', } + +export enum AnimalSexes { + MALE = 'MALE', + FEMALE = 'FEMALE', +} + +export enum AnimalOrigins { + BROUGHT_IN = 'BROUGHT_IN', + BORN_AT_FARM = 'BORN_AT_FARM', +} diff --git a/packages/webapp/src/stories/Animals/Details/AnimalDetails.stories.tsx b/packages/webapp/src/stories/Animals/Details/AnimalDetails.stories.tsx new file mode 100644 index 0000000000..170d6e7d2c --- /dev/null +++ b/packages/webapp/src/stories/Animals/Details/AnimalDetails.stories.tsx @@ -0,0 +1,78 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { Suspense } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { Meta, StoryObj } from '@storybook/react'; +import AnimalCreationDetails, { + AnimalDetailsProps, +} from '../../../components/Animals/AddAnimalsDetails'; +import AnimalDetails from '../../../components/Animals/AddAnimalsDetails'; +import { FormMethods } from '../../../components/Animals/AddAnimalsDetails/type'; +import { + typeOptions, + breedOptions, + sexOptions, + useOptions, + tagTypeOptions, + tagColorOptions, + tagPlacementOptions, + organicStatusOptions, + originOptions, +} from './mockData'; + +// https://storybook.js.org/docs/writing-stories/typescript +const meta: Meta = { + title: 'Components/AddAnimalsDetails', + component: AnimalDetails, +}; +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: () => { + const formMethods: FormMethods = useForm(); + + return ( + +
+ + + +
+
+ ); + }, +}; diff --git a/packages/webapp/src/stories/Animals/Details/General.stories.tsx b/packages/webapp/src/stories/Animals/Details/General.stories.tsx new file mode 100644 index 0000000000..f6c465f683 --- /dev/null +++ b/packages/webapp/src/stories/Animals/Details/General.stories.tsx @@ -0,0 +1,69 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { FormProvider, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { Meta, StoryObj } from '@storybook/react'; +import { componentDecorators } from '../../Pages/config/Decorators'; +import GeneralDetails, { + GeneralDetailsProps, +} from '../../../components/Animals/AddAnimalsDetails/General'; +import { AnimalOrBatchKeys } from '../../../containers/Animals/types'; +import { DetailsFields, FormMethods } from '../../../components/Animals/AddAnimalsDetails/type'; +import { typeOptions, breedOptions, sexOptions, useOptions } from './mockData'; + +// https://storybook.js.org/docs/writing-stories/typescript +const meta: Meta = { + title: 'Components/AddAnimalsDetails/General', + component: GeneralDetails, + decorators: [ + ...componentDecorators, + (Story) => { + const { t } = useTranslation(); + const formMethods: FormMethods = useForm({ mode: 'onBlur' }); + const sex = formMethods.watch(DetailsFields.SEX); + const isMaleSelected = sex === 1; + + return ( + + + + ); + }, + ], + // avoid "Maximum update depth exceeded" https://github.com/storybookjs/storybook/issues/12306 + parameters: { docs: { source: { type: 'code' } } }, +}; +export default meta; + +type Story = StoryObj; + +const commonProps = { typeOptions, breedOptions, sexOptions, useOptions }; + +export const Animal: Story = { + args: { + ...commonProps, + animalOrBatch: AnimalOrBatchKeys.ANIMAL, + }, + render: (args, context) => , +}; + +export const Batch: Story = { + args: { + ...commonProps, + animalOrBatch: AnimalOrBatchKeys.BATCH, + }, + render: (args, context) => , +}; diff --git a/packages/webapp/src/stories/Animals/Details/Origin.stories.tsx b/packages/webapp/src/stories/Animals/Details/Origin.stories.tsx new file mode 100644 index 0000000000..4fe21f5e9e --- /dev/null +++ b/packages/webapp/src/stories/Animals/Details/Origin.stories.tsx @@ -0,0 +1,58 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { FormProvider, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { Meta, StoryObj } from '@storybook/react'; +import { componentDecorators } from '../../Pages/config/Decorators'; +import Origin, { OriginProps } from '../../../components/Animals/AddAnimalsDetails/Origin'; +import { AnimalOrigins } from '../../../containers/Animals/types'; +import { DetailsFields, FormMethods } from '../../../components/Animals/AddAnimalsDetails/type'; +import { originOptions } from './mockData'; + +// https://storybook.js.org/docs/writing-stories/typescript +const meta: Meta = { + title: 'Components/AddAnimalsDetails/Origin', + component: Origin, + decorators: [ + ...componentDecorators, + (Story) => { + const { t } = useTranslation(); + const formMethods: FormMethods = useForm({ mode: 'onBlur' }); + const originId = formMethods.watch(DetailsFields.ORIGIN); + const origin = !originId + ? undefined + : originId === 1 + ? AnimalOrigins.BROUGHT_IN + : AnimalOrigins.BORN_AT_FARM; + + return ( + + + + ); + }, + ], + // avoid "Maximum update depth exceeded" https://github.com/storybookjs/storybook/issues/12306 + parameters: { docs: { source: { type: 'code' } } }, +}; +export default meta; + +type Story = StoryObj; + +export const OriginDetails: Story = { + args: { currency: '$', originOptions }, + render: (args, context) => , +}; diff --git a/packages/webapp/src/stories/Animals/Details/Other.stories.tsx b/packages/webapp/src/stories/Animals/Details/Other.stories.tsx new file mode 100644 index 0000000000..bdb31df60c --- /dev/null +++ b/packages/webapp/src/stories/Animals/Details/Other.stories.tsx @@ -0,0 +1,63 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { FormProvider, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { Meta, StoryObj } from '@storybook/react'; +import { componentDecorators } from '../../Pages/config/Decorators'; +import Other, { OtherDetailsProps } from '../../../components/Animals/AddAnimalsDetails/Other'; +import { AnimalOrBatchKeys } from '../../../containers/Animals/types'; +import { FormMethods } from '../../../components/Animals/AddAnimalsDetails/type'; +import { organicStatusOptions } from './mockData'; + +// https://storybook.js.org/docs/writing-stories/typescript +const meta: Meta = { + title: 'Components/AddAnimalsDetails/Other', + component: Other, + decorators: [ + ...componentDecorators, + (Story) => { + const { t } = useTranslation(); + const formMethods: FormMethods = useForm({ mode: 'onBlur' }); + + return ( + + + + ); + }, + ], + // avoid "Maximum update depth exceeded" https://github.com/storybookjs/storybook/issues/12306 + parameters: { docs: { source: { type: 'code' } } }, +}; +export default meta; + +type Story = StoryObj; + +export const Animal: Story = { + args: { + organicStatusOptions, + animalOrBatch: AnimalOrBatchKeys.ANIMAL, + }, + render: (args, context) => , +}; + +export const Batch: Story = { + args: { + organicStatusOptions, + animalOrBatch: AnimalOrBatchKeys.BATCH, + }, + render: (args, context) => , +}; diff --git a/packages/webapp/src/stories/Animals/Details/Unique.stories.tsx b/packages/webapp/src/stories/Animals/Details/Unique.stories.tsx new file mode 100644 index 0000000000..9b72235992 --- /dev/null +++ b/packages/webapp/src/stories/Animals/Details/Unique.stories.tsx @@ -0,0 +1,61 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { FormProvider, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { Meta, StoryObj } from '@storybook/react'; +import { componentDecorators } from '../../Pages/config/Decorators'; +import UniqueDetails, { + UniqueDetailsProps, +} from '../../../components/Animals/AddAnimalsDetails/Unique'; +import { DetailsFields, FormMethods } from '../../../components/Animals/AddAnimalsDetails/type'; +import { tagTypeOptions, tagColorOptions, tagPlacementOptions } from './mockData'; + +// https://storybook.js.org/docs/writing-stories/typescript +const meta: Meta = { + title: 'Components/AddAnimalsDetails/Unique', + component: UniqueDetails, + decorators: [ + ...componentDecorators, + (Story) => { + const { t } = useTranslation(); + const formMethods: FormMethods = useForm({ mode: 'onBlur' }); + const tagType = formMethods.watch(DetailsFields.TAG_TYPE); + const tagPlacement = formMethods.watch(DetailsFields.TAG_PLACEMENT); + const shouldShowTagTypeInput = tagType?.label === 'Other'; + const shouldShowTagPlacementInput = tagPlacement?.label === 'Other'; + + return ( + + + + ); + }, + ], + // avoid "Maximum update depth exceeded" https://github.com/storybookjs/storybook/issues/12306 + parameters: { docs: { source: { type: 'code' } } }, +}; +export default meta; + +type Story = StoryObj; + +export const Unique: Story = { + args: { tagTypeOptions, tagColorOptions, tagPlacementOptions }, + render: (args, context) => , +}; diff --git a/packages/webapp/src/stories/Animals/Details/mockData.js b/packages/webapp/src/stories/Animals/Details/mockData.js new file mode 100644 index 0000000000..76b1e19622 --- /dev/null +++ b/packages/webapp/src/stories/Animals/Details/mockData.js @@ -0,0 +1,72 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +export const typeOptions = [ + { value: 'default_1', label: 'Cattle' }, + { value: 'default_2', label: 'Pig' }, + { value: 'default_3', label: 'Chicken' }, + { value: 'custom_1', label: 'Sheep' }, +]; + +export const breedOptions = [ + { value: '1', label: 'Angus' }, + { value: '2', label: 'Cobb 5' }, +]; + +export const sexOptions = [ + { value: 0, label: `I don't know` }, + { value: 1, label: 'Male' }, + { value: 2, label: 'Female' }, +]; + +export const useOptions = [ + { label: 'A', value: 'A' }, + { label: 'B', value: 'B' }, + { label: 'C', value: 'C' }, +]; + +export const tagTypeOptions = [ + { value: 1, label: 'Ear tags' }, + { value: 2, label: 'Leg bands' }, + { value: 3, label: 'Other' }, +]; + +export const tagColorOptions = [ + { value: 1, label: 'Yellow' }, + { value: 2, label: 'White' }, + { value: 3, label: 'Orange' }, + { value: 4, label: 'Green' }, + { value: 5, label: 'Blue' }, + { value: 6, label: 'Red' }, +]; + +export const tagPlacementOptions = [ + { value: 1, label: 'Left ear' }, + { value: 2, label: 'Right ear' }, + { value: 3, label: 'Left leg' }, + { value: 4, label: 'Right leg' }, + { value: 5, label: 'Other' }, +]; + +export const organicStatusOptions = [ + { value: 1, label: 'Non-Organic' }, + { value: 2, label: 'Organic' }, + { value: 3, label: 'Transitioning' }, +]; + +export const originOptions = [ + { value: 1, label: 'Brought in' }, + { value: 2, label: 'Born at the farm' }, +]; diff --git a/packages/webapp/src/stories/ImagePicker/ImagePicker.stories.tsx b/packages/webapp/src/stories/ImagePicker/ImagePicker.stories.tsx new file mode 100644 index 0000000000..50c25b8d1a --- /dev/null +++ b/packages/webapp/src/stories/ImagePicker/ImagePicker.stories.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2024 LiteFarm.org + * This file is part of LiteFarm. + * + * LiteFarm is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiteFarm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details, see . + */ + +import { Meta, StoryObj } from '@storybook/react'; +import { componentDecorators } from '../Pages/config/Decorators'; +import ImagePicker, { type ImagePickerProps } from '../../components/ImagePicker'; + +// https://storybook.js.org/docs/writing-stories/typescript +const meta: Meta = { + title: 'Components/ImagePicker', + component: ImagePicker, + decorators: componentDecorators, + args: { + label: 'Image', + onSelectImage: () => console.log('select'), + onRemoveImage: () => console.log('remove'), + }, +}; +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; + +export const WithDefaultUrl: Story = { + args: { + defaultUrl: '/src/assets/images/certification/Farmland.svg', + }, +};