diff --git a/backend/src/integrations/Blockchain/web3/helper-functions.ts b/backend/src/integrations/Blockchain/web3/helper-functions.ts index ab18cf6fa..b894e0e9a 100644 --- a/backend/src/integrations/Blockchain/web3/helper-functions.ts +++ b/backend/src/integrations/Blockchain/web3/helper-functions.ts @@ -22,7 +22,7 @@ export function UpdateReputationActions( const subFieldCropsArray: SubFieldCrop[] = subFieldsArray[subFieldIndex].properties.crops; for(let subFieldCropIndex in subFieldCropsArray){ if(subFieldCropsArray[subFieldCropIndex].crop._id?.toString() === cropId && - subFieldCropsArray[subFieldCropIndex].farmer === farmer && + (subFieldCropsArray[subFieldCropIndex].farmer === farmer || subFieldCropsArray[subFieldCropIndex].farmer === "") && subFieldCropsArray[subFieldCropIndex].reputation_actions ){ statusUpdated = (subFieldCropsArray[subFieldCropIndex].reputation_actions![actionName] != actionStatus); diff --git a/backend/src/main.ts b/backend/src/main.ts index 2490816fb..103a33384 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -24,6 +24,7 @@ import smsRoutes from "./routes/sms-route"; import foodTrustRoutes from "./routes/food-trust-route"; import cropTemplateRoutes from "./routes/crop-template-route"; import colony from "./routes/colony-route" +import fields from "./routes/field-route" import { SocketIOManager, SocketIOManagerInstance } from "./sockets/socket.io"; import { Server } from "http"; @@ -63,6 +64,7 @@ app.use("/api/lot", lotRoutes); app.use("/api/crop", cropRoutes); app.use("/api/dashboard", dashboardRoutes); app.use("/api/recommendations", recommendationsRoutes); +app.use("/api/fields", fields); app.use("/api/weather", weatherRoutes); app.use("/api/coopManager", coopManagerRoutes); @@ -71,9 +73,9 @@ app.use("/api/messaging", messageLogRoutes); app.use("/api/sms", smsRoutes); // blockchain related routes -app.use("/api/foodtrust", foodTrustRoutes) -app.use("/api/cropTemplates", cropTemplateRoutes) -app.use("/api/colony", colony) +app.use("/api/foodtrust", foodTrustRoutes); +app.use("/api/cropTemplates", cropTemplateRoutes); +app.use("/api/colony", colony); // Static Files const publicPath = path.resolve("public"); diff --git a/backend/src/routes/crop-template-route.ts b/backend/src/routes/crop-template-route.ts index f681e636f..1e38d40a9 100644 --- a/backend/src/routes/crop-template-route.ts +++ b/backend/src/routes/crop-template-route.ts @@ -136,7 +136,7 @@ async function updateRepActions(req: Request, res: Response) { const farmerEthAddress = await farmerSigner.getAddress(); await colony.pay(farmerEthAddress, ethers.utils.parseUnits(payment.toString())); - res.json(docs); + res.status(200).json(docs); }else{ throw new Error('The request must be made with a different action status than what is existing.'); } diff --git a/backend/src/routes/field-route.ts b/backend/src/routes/field-route.ts new file mode 100644 index 000000000..f987d549c --- /dev/null +++ b/backend/src/routes/field-route.ts @@ -0,0 +1,22 @@ +import { Router, Request, Response } from "express"; +import { Field, FieldModel } from "../db/entities/field"; + +const router = Router(); + +router.get("/getFieldByFarmerId/:farmer_id", async(req: Request, res: Response) => { + try{ + const docs = await FieldModel.findOne({farmer_id: req.params.farmer_id}) + .then(doc => { + return doc; + }) + .catch(err => { + return err; + }) + res.json(docs); + }catch(e){ + console.error(e); + res.status(500).json(e); + } +}); + +export default router; \ No newline at end of file diff --git a/backend/src/routes/messaging-route.ts b/backend/src/routes/messaging-route.ts index 5e545cde6..93f553309 100644 --- a/backend/src/routes/messaging-route.ts +++ b/backend/src/routes/messaging-route.ts @@ -4,11 +4,11 @@ import { TwilioInstance } from "./../integrations/twilio/twilio.service"; import { MessageLog, MessageLogModel } from "../db/entities/messageLog"; import { getFarmerIdsFromIndex, getIndexFromFarmerIds, MessageGroup, MessageGroupModel } from "../db/entities/messageGroup"; import { FarmerModel, Farmer } from "../db/entities/farmer"; -import { MessageInterfaceSender } from "../integrations/messagingInterfaceSender"; +// import { MessageInterfaceSender } from "../integrations/messagingInterfaceSender"; const router = Router(); -const messageSender = new MessageInterfaceSender(); +// const messageSender = new MessageInterfaceSender(); router.get("/", async (req, res) => { const messages = await MessageLogModel.find({}).lean(); @@ -27,8 +27,8 @@ router.post("/sendSMSToFarmer", async (req, res) => { try { // const messageLog = await TwilioInstance.sendMessageToFarmer(farmer, message); - const messageLog = await messageSender.sendMessageToFarmer(farmer, message); - res.json(messageLog) + // const messageLog = await messageSender.sendMessageToFarmer(farmer, message); + // res.json(messageLog) } catch (e: any) { res.status(500).send(e).end(); @@ -167,18 +167,18 @@ router.post('/new-thread', async (req, res) => { try { // const messageLogs = await TwilioInstance.sendMessageToGroup(group, body.message); - const messageLogs = await messageSender.sendMessageToGroup(group, body.message); + // const messageLogs = await messageSender.sendMessageToGroup(group, body.message); - const thread: ThreadsDTO = { - thread_id: index, - farmers, - isGroup: true, - preview: body.message, - messages: messageLogs - } + // const thread: ThreadsDTO = { + // thread_id: index, + // farmers, + // isGroup: true, + // preview: body.message, + // // messages: messageLogs + // } // return res.json(messageLogs.map(it => it.messageRef)); - return res.json(thread); + // return res.json(thread); } catch (e: any) { res.status(500).send(e).end(); @@ -213,8 +213,8 @@ router.post('/thread', async (req, res) => { try { // const messageLogs = await TwilioInstance.sendMessageToGroup(group, body.message); - const messageLogs = await messageSender.sendMessageToGroup(group, body.message); - return res.json(messageLogs.map(it => it.messageRef)); + // const messageLogs = await messageSender.sendMessageToGroup(group, body.message); + // return res.json(messageLogs.map(it => it.messageRef)); } catch (e: any) { res.status(500).send(e).end(); @@ -228,8 +228,8 @@ router.post('/thread', async (req, res) => { try { // const messageLog = await TwilioInstance.sendMessageToFarmer(farmer, message); - const messageLog = await messageSender.sendMessageToFarmer(farmer, message); - res.json(messageLog) + // const messageLog = await messageSender.sendMessageToFarmer(farmer, message); + // res.json(messageLog) } catch (e: any) { res.status(500).send(e).end(); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..032c73fff --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "OpenHarvest", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/react-app/src/components/Crops/CropTemplate.tsx b/react-app/src/components/Crops/CropTemplate.tsx index 2f5d9ee90..782516a22 100644 --- a/react-app/src/components/Crops/CropTemplate.tsx +++ b/react-app/src/components/Crops/CropTemplate.tsx @@ -5,6 +5,8 @@ import { CropTemplate, CropTemplateAPI} from "../../services/cropTemplate"; import { CropService } from "../../services/CropService"; import { Crop } from "../../services/crops"; import { getFarmer, Farmer } from "../../services/farmers"; +import { Field } from "../../types/field"; +import ReputationActions from "../Farmers/ReputationActions"; import { UpdateSubFieldWithCropTemplate, OrganizeReputationActions } from './helperFunctions'; import { ColonyAPI } from '../../services/colony'; @@ -274,6 +276,7 @@ const CropTemplateSelector = () => { + ) } diff --git a/react-app/src/components/Crops/helperFunctions.tsx b/react-app/src/components/Crops/helperFunctions.tsx index 82b303907..c1ab4ac6b 100644 --- a/react-app/src/components/Crops/helperFunctions.tsx +++ b/react-app/src/components/Crops/helperFunctions.tsx @@ -36,22 +36,22 @@ export async function UpdateSubFieldWithCropTemplate( // update field.subfields.properties.crops with reputation and croptemplate in mongodb const res = await cropTemplateAPI.addCropTemplateToField(currentField); - console.log("updated field: ", res) } } export function OrganizeReputationActions(field: any): Record[]{ let reputationMaps: Record[] = [] - + const subFieldsArray: any = field.subFields; + for(let subFieldIndex in subFieldsArray){ const subFieldCropsArray: any = subFieldsArray[subFieldIndex].properties.crops; + for(let subFieldCropIndex in subFieldCropsArray){ if(subFieldCropsArray[subFieldCropIndex].reputation_actions != null){ reputationMaps.push(subFieldCropsArray[subFieldCropIndex].reputation_actions!) } } } - return reputationMaps } \ No newline at end of file diff --git a/react-app/src/components/Farmers/ReputationActions.tsx b/react-app/src/components/Farmers/ReputationActions.tsx new file mode 100644 index 000000000..781c16d4a --- /dev/null +++ b/react-app/src/components/Farmers/ReputationActions.tsx @@ -0,0 +1,109 @@ +import React, { useEffect, useState } from "react"; +import { Field } from "../../types/field"; +import { Farmer, getAllFarmers } from "../../services/farmers"; +import { Column, Row, Select, SelectItem, Toggle } from "carbon-addons-iot-react"; +import { FieldAPI } from "../../services/fields"; +import { CropTemplateAPI } from "../../services/cropTemplate" +import { OrganizeReputationActions } from '../Crops/helperFunctions'; + +const fieldAPI = new FieldAPI(); +const cropTemplateAPI = new CropTemplateAPI(); +const ReputationActions = (props: any) => { + const [field, setField] = useState(); + const [farmer, setFarmer] = useState(); + const [farmerList, setFarmerList] = useState([]); + const [reputationActionMap, setReputationActionMap] = useState({}); + + const handleClick = async(key: string) => { + + const response = await cropTemplateAPI.updateRepActions(field, props.selectedCrop, farmer!, key, true); + if(response.status === 200){ + let newReputationActionMap = [...reputationActionMap]; + newReputationActionMap[0][key] = true; + setReputationActionMap(newReputationActionMap); + } + } + + const getValueMap = (actionMap: any) => { + // console.log('actionMap: ', actionMap); + let actions = [] + for(let key in actionMap[0]) { + actions.push( + + handleClick(key)} + /> + + ) + } + return(actions); + } + + const getFarmerList = async() => { + const farmers = await getAllFarmers(); + setFarmerList(farmers); + } + + const handleFarmerSelection = async(event:any) => { + const fieldResponse = await fieldAPI.getFieldForFarmer(event.target.value); + setFarmer(event.target.value); + setField(fieldResponse); + setReputationActionMap(OrganizeReputationActions(fieldResponse)); + } + + useEffect(() => { + if(!farmerList.length){ + getFarmerList(); + } + + },[]) + + return( + <> + + + + + + {(Object.keys(reputationActionMap).length > 0) && getValueMap(reputationActionMap).map((item) => { + return( + <> + {item} + + ) + }) + } + + ) +} + +export default ReputationActions; \ No newline at end of file diff --git a/react-app/src/services/cropTemplate.tsx b/react-app/src/services/cropTemplate.tsx index 924b73535..67a315446 100644 --- a/react-app/src/services/cropTemplate.tsx +++ b/react-app/src/services/cropTemplate.tsx @@ -50,7 +50,7 @@ export class CropTemplateAPI{ actionName : actionName, actionStatus : actionStatus }); - return data.data + return data } async addCropTemplateToField(field: any): Promise { diff --git a/react-app/src/services/fields.tsx b/react-app/src/services/fields.tsx new file mode 100644 index 000000000..6c0b04bea --- /dev/null +++ b/react-app/src/services/fields.tsx @@ -0,0 +1,10 @@ +import axios from 'axios'; +import { Field } from '../types/field'; +export class FieldAPI{ + APIBase = "/api/fields/"; + + async getFieldForFarmer(farmer_id: any): Promise { + const data = await axios.get(this.APIBase + "getFieldByFarmerId/" + farmer_id); + return data.data; + } +} \ No newline at end of file