From f3c04640f2a559b1560940b7432ce8b4f18ebef8 Mon Sep 17 00:00:00 2001 From: Vivek205 Date: Fri, 2 Aug 2019 11:24:19 +0530 Subject: [PATCH 01/14] commenting SandBox App --- src/index.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index 6950b8455..5f07ec85a 100644 --- a/src/index.js +++ b/src/index.js @@ -5,17 +5,22 @@ import { Provider as ReduxProvider } from "react-redux"; import "./index.css"; import "./assets/icomoon.css"; import App from "./App"; -import SandboxApp from "./sandbox/SandboxApp"; +// import SandboxApp from "./sandbox/SandboxApp"; import configureStore from "./Redux/Store"; const store = configureStore(); -const SnetApp = () => { - if (process.env.REACT_APP_SANDBOX) { - return ; - } +// const SnetApp = () => { +// if (process.env.REACT_APP_SANDBOX) { +// return ; +// } - return ; -}; +// return ; +// }; -ReactDOM.render(, document.getElementById("root")); +ReactDOM.render( + + + , + document.getElementById("root") +); From 20e64fd169f67b06b4710abedcbd80e8afdb3509 Mon Sep 17 00:00:00 2001 From: dasari-ananya Date: Tue, 6 Aug 2019 15:58:03 +0530 Subject: [PATCH 02/14] conflict solved for index,js --- src/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.js b/src/index.js index b4805171a..75b7aba63 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,6 @@ import { Provider as ReduxProvider } from "react-redux"; import "./index.css"; import "./assets/icomoon.css"; -<<<<<<< HEAD import App from "./App"; import configureStore from "./Redux/Store"; import SnetApp from "./SnetApp"; From c00ad4f5f8259f9db07f774e5c3ed39389322c24 Mon Sep 17 00:00:00 2001 From: Vivek205 Date: Tue, 13 Aug 2019 15:29:15 +0530 Subject: [PATCH 03/14] Merge latest change from main repo (#82) * New folder for completed actions * * * Passing the parent props to the StyledTextField. * created a component for get started and addded route * working on userFeedback * re-arranged routes * submit feedback * created vertical tabs * fetchFeedbackAPI: user_address -> username * full width to tabs * converted userRating to float string * iterated throught data for categories * comfirm delete component * added get started button part * Confirm delete functionality * added features * added features data into constants also div for free trail sign up * added features data into constants also div for free trail sign up * added styling * confirm delete modal * confirm Delete popup styled * Extracting bulletPoint to separate compoent and commenting dropDown and reason * eslint:fix * worked on PR reviews * feedback functionality flow done * bifurcating endpoint CONTRACT and USER... linted SDK * added key to map iterable * react/jsx-key * arrow function has to return something * handling empty filter during filter change * proptype of Value must be number for StarRatingComponent * eslint:fix * usermenu item has no styling so no need of separate folder * moving wallet endpoint to APIEndpoints * adding styles for usermenuItem * GET_SERVICE_LIST -> USER * allowing older serviceExecutionProcess untill all the services are integrated with sdk * confirm delete error and stop loader * gitignore vscode settings * let -> const * created a method to construct myInit * deleted .vs folder * added IDE files in gitignore * New folder for completed actions * * * Passing the parent props to the StyledTextField. * working on userFeedback * submit feedback * fetchFeedbackAPI: user_address -> username * converted userRating to float string * added styling * feedback functionality flow done * bifurcating endpoint CONTRACT and USER... linted SDK * added key to map iterable * react/jsx-key * arrow function has to return something * handling empty filter during filter change * proptype of Value must be number for StarRatingComponent * eslint:fix * usermenu item has no styling so no need of separate folder * moving wallet endpoint to APIEndpoints * adding styles for usermenuItem * GET_SERVICE_LIST -> USER * allowing older serviceExecutionProcess untill all the services are integrated with sdk * let -> const * created a method to construct myInit * lint: unused var & key for map * removed unused import and refactored titles * eslint:fix * passing only the active content to FeatureMedia * separate containers for separate media types * passing content to the media containers * converted Category into a functional component * fixed media props of FeatureMedia * created a component for get started and addded route * re-arranged routes * created vertical tabs * full width to tabs * iterated throught data for categories * added get started button part * added features * added features data into constants also div for free trail sign up * added features data into constants also div for free trail sign up * worked on PR reviews * removed unused import and refactored titles * eslint:fix * passing only the active content to FeatureMedia * separate containers for separate media types * passing content to the media containers * converted Category into a functional component * fixed media props of FeatureMedia * commenting sandbox mode to fix build * Move protospec out of state * Code slipt for third party ai service components * Simplify setState * Extract SnetApp component * Make fetching of user feedback optional for sandbox mode * Disable capture feedback for sandbox mode * Reformat code * Read org_id and service_id from env for sandbox mode * new marketplace API gateway integration * removed username from feedbackSubmit * removed unnecessary prevState in setState * added useEffect to update the feedback after refetching * parsing assets for hero_image * * * working on userFeedback * submit feedback * comfirm delete component * Confirm delete functionality * confirm delete modal * confirm Delete popup styled * Extracting bulletPoint to separate compoent and commenting dropDown and reason * eslint:fix * feedback functionality flow done * usermenu item has no styling so no need of separate folder * allowing older serviceExecutionProcess untill all the services are integrated with sdk * confirm delete error and stop loader * gitignore vscode settings * deleted .vs folder * added IDE files in gitignore * new marketplace API gateway integration * removed username from feedbackSubmit * removed unnecessary prevState in setState * added useEffect to update the feedback after refetching * parsing assets for hero_image * eslint:fix * typo: legnth -> length * removed username from updateProfile * deleted commented code * syncing the props with local state * Arranged imports * renamed: generateAPIInit -> initializeAPIOptions * Move example service to new directory structure * renamed: myInit -> apiOptions * removed the componentDidUpdate * Fix lint issues * handled empty feedback * cntk img recognition using sdk * getValue() * serviceRequestComplete handler should be at the last * moved cntkImgRecon to appropriate dir heirarchy * stubs with namespace * using snakeCase for directory * updating the import Updating the import of `const CNTKImageRecognition = lazy(() => import("./snet/cntk-image-recon"));` -> `const CNTKImageRecognition = lazy(() => import("./snet/cntk_image_recon"));` to fix the code_build. * sdk integration CNTK-Language-understanding * Error Boundary for ThirdPartyAIServices * moved org_id with snet to snet folder * error boundary for AI services * stubs for face-align * setup request for face-align * loader and reset-run * isComplete and reset-run lang_understanding * parsing response face-align * isComplete and reset-run face_align * removed unused

* zeta36 chess and alpha is moved to new folder inside snet * Metering service endpoint setup * fetching metering data * added eslint disable on chess-service stubs * typo in APIEndpoints * parsing the StarRatingComponent's props * created purchase tab and its content for demo example.added styling for info box * deleted unused props * Purchase Toggler * computeActiveSection * freeCallsRemaining * added two components active session and expired session for purcahse * UserProfile Account * Grid for Account * props to StyledDropDown * Free/Regular calls * error boundary * metadata for free call * alertbox: lint * getMethodNAmes from prop * ActiveSession - Expired Session * Metering API * error handling on End * free-trial-testing changes * Simplify metadata generation * Make getMethods private * fetchAuthToke -> fetchAuthToken * Remove duplicate code * uncomment fetFreeCall and reset purchaseCompleted * returning base64 string - signature * lint:fix * fetching user Details - email & token * passing emailId to metering service * reset-run example-service * /:serviceRowId -> org/:a/service/:/b * extracted fetchAuthUser * metering: user_id -> username * commenting pricingStrategy * serviceMetaData * fetchAuthUser * facilitate serviceList -> details flow * removed redundant thro * MeteringDataSuccess * moved: freeCallsRemaining to redux * freeCallsAllowed * using dappUser gateway for metering service * alert Link * renamed fetchAuthUser -> fetchAuthenticatedUser * removed the {" "} * moved serviceMetadata -> serviceDetailsReducer * moved freeCalls -> serviceDetailsReducer * waiting for fetchMeteringData in Purchase * extracted demoProgressStatus -> enum --- .env.example | 1 + .eslintrc.json | 5 +- src/App.js | 6 +- src/Redux/actionCreators/ServiceActions.js | 16 ++-- .../actionCreators/ServiceDetailsActions.js | 51 +++++++++++ src/Redux/actionCreators/UserActions.js | 42 +++++---- src/Redux/actionCreators/index.js | 3 +- src/Redux/reducers/ServiceDetailsReducer.js | 29 ++++++ src/Redux/reducers/ServiceReducer.js | 8 +- src/Redux/reducers/index.js | 2 + src/assets/Theme.js | 7 +- .../snet/cntk_image_recon/index.js | 9 +- .../snet/cntk_language_understanding/index.js | 7 +- .../snet/example_service/index.js | 22 ++--- .../ServiceCollection/CardGroup/index.js | 2 +- src/components/Login/Signup/RenderForm.js | 3 +- .../Onboarding/Authentication/index.js | 2 +- .../TermsOfUse/PrivacyTerms/index.js | 22 ++--- .../ServiceDemo/ImageUpload/index.js | 2 +- .../Purchase/ActiveSession/index.js | 30 +++++++ .../Purchase/ActiveSession/styles.js | 25 ++++++ .../Purchase/ExpiredSession/index.js | 21 +++++ .../Purchase/ExpiredSession/styles.js | 9 ++ .../Purchase/FreeApiCalls/index.js | 15 ++++ .../ServiceDemo/Purchase/index.js | 19 ++++ .../ServiceDemo/Purchase/styles.js | 10 +++ .../ServiceDemo/PurchaseToggler.js | 12 +++ .../ServiceDemo/ThirdPartyAIService.js | 19 ++-- .../ThirdPartyServiceErrorBoundary.js | 10 +-- .../AboutService/ServiceDemo/index.js | 64 +++++++++++-- src/components/ServiceDetails/index.js | 29 +++--- .../UserProfile/UserProfileAccount/index.js | 23 +++++ .../UserProfile/UserProfileAccount/styles.js | 11 +++ .../ConfirmDelete/index.js | 2 +- src/components/UserProfile/index.js | 6 +- src/components/common/AlertBox/AlertLink.js | 14 +++ src/components/common/AlertBox/index.js | 11 ++- src/components/common/AlertBox/styles.js | 12 +++ src/components/common/Header/HeaderActions.js | 1 - src/components/common/StyledDropdown/index.js | 12 ++- .../common/StyledLinearProgress/index.js | 11 +++ .../common/StyledLinearProgress/styles.js | 9 ++ src/config/APIEndpoints.js | 7 ++ src/utility/constants/UserPopupMenu.js | 6 ++ src/utility/sdk.js | 90 +++++++++++-------- 45 files changed, 568 insertions(+), 149 deletions(-) create mode 100644 src/Redux/actionCreators/ServiceDetailsActions.js create mode 100644 src/Redux/reducers/ServiceDetailsReducer.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/index.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/styles.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/index.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/styles.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/FreeApiCalls/index.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/index.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/styles.js create mode 100644 src/components/ServiceDetails/AboutService/ServiceDemo/PurchaseToggler.js create mode 100644 src/components/UserProfile/UserProfileAccount/index.js create mode 100644 src/components/UserProfile/UserProfileAccount/styles.js create mode 100644 src/components/common/AlertBox/AlertLink.js create mode 100644 src/components/common/StyledLinearProgress/index.js create mode 100644 src/components/common/StyledLinearProgress/styles.js diff --git a/.env.example b/.env.example index d33e06a71..f10151c4d 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ REACT_APP_CONTRACT_ENDPOINT= REACT_APP_USER_ENDPOINT= +REACT_APP_SIGNER_ENDPOINT= REACT_APP_SERVICE_PROTOBUF_ENDPOINT= REACT_APP_SERVICE_EXECUTION_ENDPOINT= REACT_APP_AWS_IDENTITY_POOL_ID= diff --git a/.eslintrc.json b/.eslintrc.json index 0db9d4728..39295f993 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -25,8 +25,9 @@ "html": true } ], - "no-extra-boolean-cast": 0, + "no-extra-boolean-cast": "off", "no-unused-vars": "error", - "react/jsx-key": "error" + "react/jsx-key": "error", + "no-useless-computed-key": "error" } } diff --git a/src/App.js b/src/App.js index 7a5ed0ff8..1cf1ac4ad 100644 --- a/src/App.js +++ b/src/App.js @@ -33,10 +33,6 @@ class App extends Component { this.props.fetchUserDetails(); }; - componentDidMount = () => { - this.props.fetchUserDetails(); - }; - render() { const { hamburgerMenu, isInitialized, isLoggedIn } = this.props; if (!isInitialized) { @@ -77,7 +73,7 @@ class App extends Component { component={withInAppWrapper(AiMarketplace)} /> diff --git a/src/Redux/actionCreators/ServiceActions.js b/src/Redux/actionCreators/ServiceActions.js index b8fc16745..59ee545bd 100644 --- a/src/Redux/actionCreators/ServiceActions.js +++ b/src/Redux/actionCreators/ServiceActions.js @@ -5,7 +5,7 @@ import { APIEndpoints, APIPaths } from "../../config/APIEndpoints"; import GRPCProtoV3Spec from "../../assets/models/GRPCProtoV3Spec"; import { loaderActions } from "./"; import { LoaderContent } from "../../utility/constants/LoaderContent"; -import { PricingStrategy } from "../../utility/PricingStrategy.js"; +// import { PricingStrategy } from "../../utility/PricingStrategy.js"; import { initializeAPIOptions } from "../../utility/API"; export const UPDATE_SERVICE_LIST = "SET_SERVICE_LIST"; @@ -33,13 +33,13 @@ export const fetchServiceSuccess = res => dispatch => { total_count: res.data.total_count, }, }); - if (res.data.total_count > 0) { - res.data.result.map(service => { - const pricing = service["pricing"]; - let pricingJSON = typeof pricing === "undefined" || pricing === null ? JSON.stringify(service) : pricing; - service.pricing_strategy = new PricingStrategy(pricingJSON); - }); - } + // if (res.data.total_count > 0) { + // res.data.result.map(service => { + // const pricing = service["pricing"]; + // let pricingJSON = typeof pricing === "undefined" || pricing === null ? JSON.stringify(service) : pricing; + // service.pricing_strategy = new PricingStrategy(pricingJSON); + // }); + // } dispatch({ type: UPDATE_SERVICE_LIST, payload: res.data.result }); dispatch(loaderActions.stopAIServiceListLoader); }; diff --git a/src/Redux/actionCreators/ServiceDetailsActions.js b/src/Redux/actionCreators/ServiceDetailsActions.js new file mode 100644 index 000000000..2d1a092c8 --- /dev/null +++ b/src/Redux/actionCreators/ServiceDetailsActions.js @@ -0,0 +1,51 @@ +import { API } from "aws-amplify"; + +import { APIEndpoints, APIPaths } from "../../config/APIEndpoints"; +import { initializeAPIOptions } from "../../utility/API"; +import { fetchAuthenticatedUser } from "./UserActions"; + +export const UPDATE_SERVICE_METADATA = "UPDATE_SERVICE_METADATA"; +export const RESET_SERVICE_METADATA = "RESET_SERVICE_METADATA"; +export const UPDATE_FREE_CALLS_ALLOWED = "UPDATE_FREE_CALLS_ALLOWED"; +export const UPDATE_FREE_CALLS_REMAINING = "UPDATE_FREE_CALLS_REMAINING"; + +const resetServiceMetadata = dispatch => { + dispatch({ type: RESET_SERVICE_METADATA }); +}; +const fetchServiceMetadataSuccess = serviceMetadata => dispatch => { + dispatch({ type: UPDATE_SERVICE_METADATA, payload: serviceMetadata }); +}; + +const fetchServiceMetadataAPI = async ({ orgId, serviceId }) => { + const url = `${APIEndpoints.CONTRACT.endpoint}/org/${orgId}/service/${serviceId}/group`; + const response = await fetch(url); + return response.json(); +}; + +export const fetchServiceMetadata = ({ orgId, serviceId }) => async dispatch => { + if (process.env.REACT_APP_SANDBOX) { + return {}; + } + dispatch(resetServiceMetadata); + const serviceMetadata = await fetchServiceMetadataAPI({ orgId, serviceId }); + dispatch(fetchServiceMetadataSuccess(serviceMetadata)); +}; + +const fetchMeteringDataSuccess = usageData => dispatch => { + const freeCallsRemaining = usageData.free_calls_allowed - usageData.total_calls_made; + dispatch({ type: UPDATE_FREE_CALLS_ALLOWED, payload: usageData.free_calls_allowed }); + dispatch({ type: UPDATE_FREE_CALLS_REMAINING, payload: freeCallsRemaining }); +}; + +const meteringAPI = (token, orgId, serviceId, userId) => { + const apiName = APIEndpoints.USER.name; + const apiPath = `${APIPaths.FREE_CALL_USAGE}?organization_id=${orgId}&service_id=${serviceId}&username=${userId}`; + const apiOptions = initializeAPIOptions(token); + return API.get(apiName, apiPath, apiOptions); +}; + +export const fetchMeteringData = ({ orgId, serviceId }) => async dispatch => { + const { email, token } = await fetchAuthenticatedUser(); + const usageData = await meteringAPI(token, orgId, serviceId, email); + return dispatch(fetchMeteringDataSuccess(usageData)); +}; diff --git a/src/Redux/actionCreators/UserActions.js b/src/Redux/actionCreators/UserActions.js index 8e38ccb4c..5a9474a7c 100644 --- a/src/Redux/actionCreators/UserActions.js +++ b/src/Redux/actionCreators/UserActions.js @@ -19,6 +19,16 @@ export const UNSUBSCRIBE_TO_EMAIL_ALERTS = "UNSUBSCRIBE_TO_EMAIL_ALERTS"; export const WALLET_CREATION_SUCCESS = "WALLET_CREATION_SUCCESS"; export const APP_INITIALIZATION_SUCCESS = "APP_INITIALIZATION_SUCCESS"; +export const fetchAuthenticatedUser = async () => { + const currentUser = await Auth.currentAuthenticatedUser({ bypassCache: true }); + return { + username: currentUser.username, + email: currentUser.attributes.email, + email_verified: currentUser.attributes.email_verified, + token: currentUser.signInUserSession.idToken.jwtToken, + }; +}; + export const appInitializationSuccess = dispatch => { dispatch({ type: APP_INITIALIZATION_SUCCESS, payload: { isInitialized: true } }); }; @@ -90,32 +100,25 @@ const fetchUserDetailsError = err => dispatch => { export const fetchUserDetails = async dispatch => { try { - const currentUser = await Auth.currentAuthenticatedUser({ bypassCache: true }); - const wallet = await fetchWalletStatus(currentUser.username, currentUser.signInUserSession.idToken.jwtToken); - dispatch(fetchUserProfile(currentUser.username, currentUser.signInUserSession.idToken.jwtToken)); - if (currentUser === null || currentUser === undefined) { + const { username, token, email, email_verified } = await fetchAuthenticatedUser(); + const wallet = await fetchWalletStatus(username, token); + dispatch(fetchUserProfile(username, token)); + if (username === null || username === undefined) { dispatch(noAuthenticatedUser); return; } - if (currentUser.attributes && currentUser.attributes.email_verified) { - dispatch( - fetchUserDetailsSuccess( - currentUser.attributes.email_verified, - currentUser.attributes.email, - currentUser.username, - wallet.data.length > 0 - ) - ); + if (email_verified) { + dispatch(fetchUserDetailsSuccess(email_verified, email, username, wallet.data.length > 0)); } } catch (err) { dispatch(fetchUserDetailsError(err)); } }; -export const updateUserProfileInit = (currentUser, updatedUserData) => { +export const updateUserProfileInit = (token, updatedUserData) => { const apiName = APIEndpoints.USER.name; const path = APIPaths.UPDATE_USER_PROFILE; - const apiOptions = initializeAPIOptions(currentUser.signInUserSession.idToken.jwtToken, updatedUserData); + const apiOptions = initializeAPIOptions(token, updatedUserData); return API.post(apiName, path, apiOptions); }; @@ -136,8 +139,8 @@ const updateUserProfileFailure = err => dispatch => { export const updateUserProfile = updatedUserData => async dispatch => { dispatch(loaderActions.startAppLoader(LoaderContent.UPDATE_PROFILE)); try { - const currentUser = await Auth.currentAuthenticatedUser({ bypassCache: true }); - const response = await updateUserProfileInit(currentUser, updatedUserData); + const { token } = await fetchAuthenticatedUser(); + const response = await updateUserProfileInit(token, updatedUserData); if (response.status === "success") { return dispatch(updateUserProfileSuccess(updatedUserData)); } @@ -198,8 +201,8 @@ const registrationAPI = token => { }; export const registerInMarketplace = async dispatch => { - const currentUser = await Auth.currentAuthenticatedUser({ bypassCache: true }); - return registrationAPI(currentUser.signInUserSession.idToken.jwtToken); + const { token } = await fetchAuthenticatedUser(); + return registrationAPI(token); }; export const signOut = dispatch => { @@ -227,6 +230,7 @@ export const signOut = dispatch => { dispatch(loaderActions.stopAppLoader); }); }; + export const walletCreationSuccess = dispatch => { dispatch({ type: WALLET_CREATION_SUCCESS, payload: { isWalletAssigned: true } }); }; diff --git a/src/Redux/actionCreators/index.js b/src/Redux/actionCreators/index.js index 7b3d0f68b..9d4b6144a 100644 --- a/src/Redux/actionCreators/index.js +++ b/src/Redux/actionCreators/index.js @@ -1,7 +1,8 @@ import * as userActions from "./UserActions"; import * as serviceActions from "./ServiceActions"; +import * as serviceDetailsActions from "./ServiceDetailsActions"; import * as errorActions from "./ErrorActions"; import * as loaderActions from "./LoaderActions"; import * as stylesActions from "./StylesActions"; -export { userActions, serviceActions, errorActions, loaderActions, stylesActions }; +export { userActions, serviceActions, serviceDetailsActions, errorActions, loaderActions, stylesActions }; diff --git a/src/Redux/reducers/ServiceDetailsReducer.js b/src/Redux/reducers/ServiceDetailsReducer.js new file mode 100644 index 000000000..7e56a8986 --- /dev/null +++ b/src/Redux/reducers/ServiceDetailsReducer.js @@ -0,0 +1,29 @@ +import { serviceDetailsActions } from "../actionCreators"; + +const InitialServiceDetails = { + serviceMetadata: {}, + freeCallsRemaining: 0, + freeCallsAllowed: 0, +}; + +const serviceDetailsReducer = (state = InitialServiceDetails, action) => { + switch (action.type) { + case serviceDetailsActions.RESET_SERVICE_METADATA: { + return { ...state, serviceMetadata: {} }; + } + case serviceDetailsActions.UPDATE_SERVICE_METADATA: { + return { ...state, serviceMetadata: action.payload }; + } + case serviceDetailsActions.UPDATE_FREE_CALLS_ALLOWED: { + return { ...state, freeCallsAllowed: action.payload }; + } + case serviceDetailsActions.UPDATE_FREE_CALLS_REMAINING: { + return { ...state, freeCallsRemaining: action.payload }; + } + default: { + return state; + } + } +}; + +export default serviceDetailsReducer; diff --git a/src/Redux/reducers/ServiceReducer.js b/src/Redux/reducers/ServiceReducer.js index db357528b..1e480e7e3 100644 --- a/src/Redux/reducers/ServiceReducer.js +++ b/src/Redux/reducers/ServiceReducer.js @@ -3,6 +3,7 @@ import { defaultListingConfig, defaultActiveFilterItem } from "../../utility/con const InitialServiceList = { services: [], + serviceMetadata: {}, pagination: { ...defaultListingConfig }, filterData: { org_id: [], @@ -22,6 +23,9 @@ const serviceReducer = (state = InitialServiceList, action) => { case serviceActions.UPDATE_SERVICE_LIST: { return { ...state, services: action.payload }; } + case serviceActions.UPDATE_SERVICE_METADATA: { + return { ...state, serviceMetadata: { ...action.payload } }; + } case serviceActions.UPDATE_SERVICE_EXECUTION_RESPONSE: { return { ...state, serviceMethodExecution: { ...state.serviceMethodExecution, ...action.payload } }; } @@ -77,6 +81,6 @@ const serviceReducer = (state = InitialServiceList, action) => { export default serviceReducer; -export const serviceDetails = (state, serviceRowId) => { - return state.serviceReducer.services.find(service => service.service_row_id === Number(serviceRowId)); +export const serviceDetails = (state, { orgId, serviceId }) => { + return state.serviceReducer.services.find(service => service.org_id === orgId && service.service_id === serviceId); }; diff --git a/src/Redux/reducers/index.js b/src/Redux/reducers/index.js index b800143c6..b74be3693 100644 --- a/src/Redux/reducers/index.js +++ b/src/Redux/reducers/index.js @@ -1,6 +1,7 @@ import { combineReducers } from "redux"; import userReducer from "./UserReducer"; import serviceReducer from "./ServiceReducer"; +import serviceDetailsReducer from "./ServiceDetailsReducer"; import errorReducer from "./ErrorReducer"; import loaderReducer from "./LoaderReducer"; import stylesReducer from "./StylesReducer"; @@ -8,6 +9,7 @@ import stylesReducer from "./StylesReducer"; const rootReducer = combineReducers({ userReducer, serviceReducer, + serviceDetailsReducer, errorReducer, loaderReducer, stylesReducer, diff --git a/src/assets/Theme.js b/src/assets/Theme.js index a1eb0af58..cdcde2afa 100644 --- a/src/assets/Theme.js +++ b/src/assets/Theme.js @@ -11,7 +11,10 @@ const alertBoxBorder = "#E67381"; const alertBoxBackgroundColor = "#FDE5E8"; const warningBoxBg = "#FDF3E5"; -const warningBoxBorder = "#F18D5A;"; +const warningBoxBorder = "#F18D5A"; + +const infoBoxBg = "#DEEAFF"; +const infoBoxLink = "#067AD7"; const userProfileIconColor = "#757575"; @@ -100,6 +103,8 @@ const theme = createMuiTheme({ redBtnBg, warningBoxBorder, warningBoxBg, + infoBoxBg, + infoBoxLink, }, }, typography: { diff --git a/src/assets/thirdPartyServices/snet/cntk_image_recon/index.js b/src/assets/thirdPartyServices/snet/cntk_image_recon/index.js index 5563a4ea6..74781e7dd 100644 --- a/src/assets/thirdPartyServices/snet/cntk_image_recon/index.js +++ b/src/assets/thirdPartyServices/snet/cntk_image_recon/index.js @@ -2,7 +2,6 @@ import React from "react"; import Button from "@material-ui/core/Button"; import { Recognizer } from "./image_recon_pb_service"; -import { getMethodNames } from "../../../../utility/sdk"; import MethodNamesDropDown from "../../common/MethodNamesDropDown"; import SNETImageUpload from "../../standardComponents/SNETImageUpload"; @@ -50,7 +49,11 @@ export default class CNTKImageRecognition extends React.Component { const props = { request, - onEnd: ({ message }) => { + onEnd: response => { + const { message, status, statusMessage } = response; + if (status !== 0) { + throw new Error(statusMessage); + } this.setState({ ...initialUserInput, response: { status: "success", top_5: message.getTop5(), delta_time: message.getDeltaTime() }, @@ -62,7 +65,7 @@ export default class CNTKImageRecognition extends React.Component { } renderForm() { - const serviceNameOptions = ["Select a method", ...getMethodNames(Recognizer)]; + const serviceNameOptions = ["Select a method", ...this.props.serviceClient.getMethodNames(Recognizer)]; return ( diff --git a/src/assets/thirdPartyServices/snet/cntk_language_understanding/index.js b/src/assets/thirdPartyServices/snet/cntk_language_understanding/index.js index fec4f52a9..fc148062b 100644 --- a/src/assets/thirdPartyServices/snet/cntk_language_understanding/index.js +++ b/src/assets/thirdPartyServices/snet/cntk_language_understanding/index.js @@ -2,7 +2,6 @@ import React from "react"; import Button from "@material-ui/core/Button"; import { LanguageUnderstanding } from "./language_understanding_pb_service"; -import { getMethodNames } from "../../../../utility/sdk"; import MethodNamesDropDown from "../../common/MethodNamesDropDown"; const initialUserInput = { @@ -80,8 +79,8 @@ export default class CNTKLanguageUnderstanding extends React.Component { const props = { request, - onEnd: resp => { - const { message, status, statusMessage } = resp; + onEnd: response => { + const { message, status, statusMessage } = response; if (status !== 0) { throw new Error(statusMessage); } @@ -95,7 +94,7 @@ export default class CNTKLanguageUnderstanding extends React.Component { } renderForm() { - const serviceNameOptions = ["select a method", ...getMethodNames(LanguageUnderstanding)]; + const serviceNameOptions = ["select a method", ...this.props.serviceClient.getMethodNames(LanguageUnderstanding)]; return (

diff --git a/src/assets/thirdPartyServices/snet/example_service/index.js b/src/assets/thirdPartyServices/snet/example_service/index.js index d9a541309..ce79c84b7 100644 --- a/src/assets/thirdPartyServices/snet/example_service/index.js +++ b/src/assets/thirdPartyServices/snet/example_service/index.js @@ -1,7 +1,8 @@ import React from "react"; import { Calculator } from "./example_service_pb_service"; -import { getMethodNames } from "../../../../utility/sdk"; + +const initialUserInput = { methodName: "Select a method", a: 0, b: 0 }; export default class ExampleService extends React.Component { constructor(props) { @@ -9,11 +10,7 @@ export default class ExampleService extends React.Component { this.submitAction = this.submitAction.bind(this); this.handleFormUpdate = this.handleFormUpdate.bind(this); - this.state = { - methodName: "Select a method", - a: 0, - b: 0, - }; + this.state = { ...initialUserInput }; } canBeInvoked() { @@ -44,9 +41,12 @@ export default class ExampleService extends React.Component { const props = { request, - onEnd: ({ code, statusMessage, headers, message, trailers }) => { - this.setState({ isComplete: true, response: { value: message.getValue() }}); - } + onEnd: ({ status, statusMessage, message }) => { + if (status !== 0) { + throw new Error(statusMessage); + } + this.setState({ ...initialUserInput, response: { value: message.getValue() } }); + }, }; this.props.serviceClient.unary(methodDescriptor, props); } @@ -59,7 +59,7 @@ export default class ExampleService extends React.Component { } renderForm() { - const serviceMethodNames = getMethodNames(Calculator); + const serviceMethodNames = this.props.serviceClient.getMethodNames(Calculator); return (
@@ -144,7 +144,7 @@ export default class ExampleService extends React.Component { } render() { - if (this.state.isComplete) return
{this.renderComplete()}
; + if (this.props.isComplete) return
{this.renderComplete()}
; else { return
{this.renderForm()}
; } diff --git a/src/components/AiMarketplace/MainSection/ServiceCollection/CardGroup/index.js b/src/components/AiMarketplace/MainSection/ServiceCollection/CardGroup/index.js index 1f4650c3c..b21862de5 100644 --- a/src/components/AiMarketplace/MainSection/ServiceCollection/CardGroup/index.js +++ b/src/components/AiMarketplace/MainSection/ServiceCollection/CardGroup/index.js @@ -26,7 +26,7 @@ const CardGroup = ({ cards, loading }) => { {cards.map(card => (

Sign up now to get a free account!

- {" "} Gain instant access to an ever-growing collection of unique, privacy-preserving AI services for your company - or personal use.{" "} + or personal use.

  • diff --git a/src/components/Onboarding/Authentication/index.js b/src/components/Onboarding/Authentication/index.js index df695b9f5..2e8a08154 100644 --- a/src/components/Onboarding/Authentication/index.js +++ b/src/components/Onboarding/Authentication/index.js @@ -69,7 +69,7 @@ class Authentication extends Component {

    Please enter the verification code below to confirm your email address. Check your spam, or junk folders if you encounter any delays. The email should be from otp@singularitynet.io. The code will be valid for 5 - minutes.{" "} + minutes.

    {  website and all content, services and products available at or through the website, including, but not - limited to,{" "} + limited to, SingularityNET.io @@ -29,7 +29,7 @@ const PrivacyTerms = () => {  Hosting service (“Hosting”), (taken together, the Website). The Website is owned and operated by Stichting SingularityNET (“SingularityNET”). The Website is offered subject to your acceptance without modification of all of the terms and conditions contained herein and all other operating - rules, policies (including, without limitation,{" "} + rules, policies (including, without limitation, SingularityNET.io @@ -248,7 +248,7 @@ const PrivacyTerms = () => {

    We have not reviewed, and cannot review, all of the material, including computer software, made available - through the websites and webpages to which{" "} + through the websites and webpages to which SingularityNET.io @@ -262,7 +262,7 @@ const PrivacyTerms = () => { SingularityNET.io - websites and webpages, and is not responsible for their contents or their use. By linking to a non -{" "} + websites and webpages, and is not responsible for their contents or their use. By linking to a non - SingularityNET.io @@ -271,7 +271,7 @@ const PrivacyTerms = () => {  website or webpage, SingularityNET does not represent or imply that it endorses such website or webpage. You are responsible for taking precautions as necessary to protect yourself and your computer systems from viruses, worms, Trojan horses, and other harmful or destructive content. SingularityNET - disclaims any responsibility for any harm resulting from your use of{" "} + disclaims any responsibility for any harm resulting from your use of non-SingularityNET.io @@ -286,14 +286,14 @@ const PrivacyTerms = () => {

    As SingularityNET asks others to respect its intellectual property rights, it respects the intellectual - property rights of others. If you believe that material located on or linked to by{" "} + property rights of others. If you believe that material located on or linked to by SingularityNET.io violates your copyright, and if this website resides in the USA, you are encouraged to notify SingularityNET - in accordance with SingularityNET’s{" "} + in accordance with SingularityNET’s @@ -318,7 +318,7 @@ const PrivacyTerms = () => { This Agreement does not transfer from SingularityNET to you any SingularityNET or third party intellectual property, and all right, title and interest in and to such property will remain (as between the parties) - solely with SingularityNET. SingularityNET,{" "} + solely with SingularityNET. SingularityNET, SingularityNET.io @@ -367,7 +367,7 @@ const PrivacyTerms = () => {

    SingularityNET may terminate your access to all or any part of the Website at any time, with or without - cause, with or without notice, effective immediately. If you wish to terminate this Agreement or your{" "} + cause, with or without notice, effective immediately. If you wish to terminate this Agreement or your SingularityNET.io @@ -389,7 +389,7 @@ const PrivacyTerms = () => { all warranties of any kind, express or implied, including, without limitation, the warranties of merchantability, fitness for a particular purpose and non-infringement. Neither SingularityNET nor its suppliers and licensors, makes any warranty that the Website will be error free or that access thereto will - be continuous or uninterrupted. If you’re actually reading this, here’s{" "} + be continuous or uninterrupted. If you’re actually reading this, here’s @@ -425,7 +425,7 @@ const PrivacyTerms = () => {

    You represent and warrant that (i) your use of the Website will be in strict accordance with the - SingularityNET{" "} + SingularityNET Privacy Policy diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/ImageUpload/index.js b/src/components/ServiceDetails/AboutService/ServiceDemo/ImageUpload/index.js index 10403fd25..6a5bb3abe 100644 --- a/src/components/ServiceDetails/AboutService/ServiceDemo/ImageUpload/index.js +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/ImageUpload/index.js @@ -20,7 +20,7 @@ const ImageUpload = ({ classes, imageType }) => {

    - Drag and drop image here or{" "} + Drag and drop image here or click diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/index.js b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/index.js new file mode 100644 index 000000000..f1804352e --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/index.js @@ -0,0 +1,30 @@ +import React from "react"; +import { withStyles } from "@material-ui/styles"; + +import AlertBox from "../../../../../common/AlertBox"; +import StyledButton from "../../../../../common/StyledButton"; +import StyledLinearProgress from "../../../../../common/StyledLinearProgress"; +import { useStyles } from "./styles"; + +const ActiveSession = ({ classes, freeCallsRemaining, handleComplete, freeCallsAllowed }) => { + const progressValue = () => (freeCallsRemaining / freeCallsAllowed) * 100; + + return ( +
    + +
    + Free API Calls + {freeCallsRemaining} + + +
    +
    + ); +}; + +export default withStyles(useStyles)(ActiveSession); diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/styles.js b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/styles.js new file mode 100644 index 000000000..5fce912b8 --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ActiveSession/styles.js @@ -0,0 +1,25 @@ +export const useStyles = theme => ({ + FreeApiCallsData: { + marginTop: 30, + textAlign: "center", + "& > div": { textAlign: "center" }, + "& button": { + padding: "13px 50px 11px", + marginTop: 30, + marginRight: "0 !important", + }, + }, + FreeApiCallsText: { + display: "block", + color: theme.palette.text.lightShadedGray, + fontSize: 12, + lineHeight: "17px", + textTransform: "uppercase", + }, + ReaminaingCallsNo: { + color: theme.palette.text.darkShadedGray, + fontSize: 24, + fontWeight: 600, + lineHeight: "33px", + }, +}); diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/index.js b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/index.js new file mode 100644 index 000000000..4ce60df60 --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/index.js @@ -0,0 +1,21 @@ +import React from "react"; +import { withStyles } from "@material-ui/styles"; + +import AlertBox from "../../../../../common/AlertBox"; +import StyledButton from "../../../../../common/StyledButton"; +import { useStyles } from "./styles"; + +const ExpiredSession = ({ classes, handleComplete }) => { + return ( +
    + + +
    + ); +}; + +export default withStyles(useStyles)(ExpiredSession); diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/styles.js b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/styles.js new file mode 100644 index 000000000..b2aa8c1a6 --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/ExpiredSession/styles.js @@ -0,0 +1,9 @@ +export const useStyles = theme => ({ + ExpiredSessionContainer: { + textAlign: "center", + "& button": { + marginTop: 36, + marginRight: "0 !important", + }, + }, +}); diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/FreeApiCalls/index.js b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/FreeApiCalls/index.js new file mode 100644 index 000000000..20d298c06 --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/FreeApiCalls/index.js @@ -0,0 +1,15 @@ +import React from "react"; + +import AlertBox from "../../../../../common/AlertBox"; + +const FreeApiCalls = ({ classes, freeCallsRemaining }) => { + return ( + + ); +}; + +export default FreeApiCalls; diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/index.js b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/index.js new file mode 100644 index 000000000..24a2f047a --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/index.js @@ -0,0 +1,19 @@ +import React from "react"; + +import ActiveSession from "./ActiveSession"; +import ExpiredSession from "./ExpiredSession"; + +const Purchase = ({ handleComplete, freeCallsRemaining, freeCallsAllowed }) => { + if (freeCallsRemaining > 0) { + return ( + + ); + } + return ; +}; + +export default Purchase; diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/styles.js b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/styles.js new file mode 100644 index 000000000..f8dd842dd --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/Purchase/styles.js @@ -0,0 +1,10 @@ +export const useStyles = theme => ({ + PurchaseDescription: { + marginTop: 33, + color: theme.palette.text.alertBoxColor, + fontFamily: theme.typography.secondary.main, + fontSize: 14, + letterSpacing: 0.25, + lineHeight: "21px", + }, +}); diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/PurchaseToggler.js b/src/components/ServiceDetails/AboutService/ServiceDemo/PurchaseToggler.js new file mode 100644 index 000000000..5738e7dad --- /dev/null +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/PurchaseToggler.js @@ -0,0 +1,12 @@ +import React from "react"; +import ThirdPartyAIService from "./ThirdPartyAIService"; +import Purchase from "./Purchase"; + +const PurchaseToggler = ({ purchaseCompleted, purchaseProps, thirdPartyProps }) => { + if (purchaseCompleted) { + return ; + } + return ; +}; + +export default PurchaseToggler; diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyAIService.js b/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyAIService.js index 8ac4c356e..224388e14 100644 --- a/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyAIService.js +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyAIService.js @@ -4,10 +4,10 @@ import { withStyles } from "@material-ui/styles"; import thirdPartyCustomUIComponents from "../../../../assets/thirdPartyServices"; import { useStyles } from "./styles"; -import { serviceActions, loaderActions } from "../../../../Redux/actionCreators"; +import { serviceActions, serviceDetailsActions, loaderActions } from "../../../../Redux/actionCreators"; import { APIEndpoints } from "../../../../config/APIEndpoints"; import CompletedActions from "./CompletedActions"; -import { createServiceClient } from "../../../../utility/sdk"; +import { createServiceClient, callTypes } from "../../../../utility/sdk"; import ThirdPartyServiceErrorBoundary from "./ThirdPartyServiceErrorBoundary"; import { LoaderContent } from "../../../../utility/constants/LoaderContent"; @@ -22,13 +22,15 @@ class ThirdPartyAIService extends Component { }; componentDidMount = async () => { - const { org_id, service_id, username } = this.props; + const { org_id, service_id, freeCallsRemaining, serviceMetadata } = this.props; + const callType = freeCallsRemaining > 0 ? callTypes.FREE : callTypes.REGULAR; this.serviceClient = await createServiceClient( org_id, service_id, - username, + serviceMetadata, this.serviceRequestStartHandler, - this.serviceRequestCompleteHandler + this.serviceRequestCompleteHandler, + callType ); await this.setupComponent(); this.setState({ loading: false }); @@ -51,6 +53,10 @@ class ThirdPartyAIService extends Component { }; serviceRequestCompleteHandler = () => { + const { org_id, service_id, fetchMeteringData, freeCallsRemaining } = this.props; + if (freeCallsRemaining > 0) { + fetchMeteringData({ orgId: org_id, serviceId: service_id }); + } this.setState({ serviceRequestComplete: true }); this.props.stopLoader(); }; @@ -137,7 +143,9 @@ const mapStateToProps = state => ({ grpcResponse: state.serviceReducer.serviceMethodExecution.response, isComplete: state.serviceReducer.serviceMethodExecution.isComplete, username: state.userReducer.username, + serviceMetadata: state.serviceDetailsReducer.serviceMetadata, }); + const mapDispatchToProps = dispatch => ({ fetchProtoSpec: servicebufURL => dispatch(serviceActions.fetchProtoSpec(servicebufURL)), invokeServiceMethod: data => dispatch(serviceActions.invokeServiceMethod(data)), @@ -145,6 +153,7 @@ const mapDispatchToProps = dispatch => ({ stopLoader: () => dispatch(loaderActions.stopAppLoader), resetServiceExecution: () => dispatch(serviceActions.resetServiceExecution), fetchFeedback: (orgId, serviceId) => dispatch(serviceActions.fetchFeedback(orgId, serviceId)), + fetchMeteringData: args => dispatch(serviceDetailsActions.fetchMeteringData({ ...args })), }); export default connect( diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyServiceErrorBoundary.js b/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyServiceErrorBoundary.js index ea9585408..815a30ce5 100644 --- a/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyServiceErrorBoundary.js +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/ThirdPartyServiceErrorBoundary.js @@ -1,5 +1,6 @@ import React, { Component } from "react"; +import AlertBox, { alertTypes } from "../../../common/AlertBox"; class ThirdPartyServiceErrorBoundary extends Component { state = { error: undefined, @@ -15,15 +16,10 @@ class ThirdPartyServiceErrorBoundary extends Component { }; render() { - const { error, info } = this.state; + const { error } = this.state; if (error) { - return ( -

    - Err: - {info} -

    - ); + return ; } return this.props.children; diff --git a/src/components/ServiceDetails/AboutService/ServiceDemo/index.js b/src/components/ServiceDetails/AboutService/ServiceDemo/index.js index 718339fc7..f29ddb420 100644 --- a/src/components/ServiceDetails/AboutService/ServiceDemo/index.js +++ b/src/components/ServiceDetails/AboutService/ServiceDemo/index.js @@ -4,30 +4,76 @@ import { connect } from "react-redux"; import ProgressBar from "../../../common/ProgressBar"; import { useStyles } from "./styles"; -import ThirdPartyAIService from "./ThirdPartyAIService"; +import { serviceDetailsActions } from "../../../../Redux/actionCreators"; +import PurchaseToggler from "./PurchaseToggler"; + +const demoProgressStatus = { + purchasing: 1, + executingAIservice: 2, + displayingResponse: 3, +}; class ServiceDemo extends Component { state = { error: "error state message", - progressText: ["Configure", "Results"], + progressText: ["Purchase", "Configure", "Results"], + purchaseCompleted: false, + }; + + componentDidMount = async () => { + await this.fetchFreeCallsUsage(); + }; + + fetchFreeCallsUsage = () => { + const { service, fetchMeteringData, email } = this.props; + return fetchMeteringData({ + orgId: service.org_id, + serviceId: service.service_id, + username: email, + }); + }; + + computeActiveSection = () => { + const { purchaseCompleted } = this.state; + const { isServiceExecutionComplete } = this.props; + const { purchasing, executingAIservice, displayingResponse } = demoProgressStatus; + + return purchaseCompleted ? (isServiceExecutionComplete ? displayingResponse : executingAIservice) : purchasing; + }; + + handlePurchaseComplete = () => { + this.setState({ purchaseCompleted: true }); }; render() { - const { classes, service, isComplete } = this.props; - const { progressText } = this.state; + const { classes, service, freeCallsRemaining, freeCallsAllowed } = this.props; + const { progressText, purchaseCompleted } = this.state; return (

    Process

    - -

    {this.props.tutorial}

    - + +
    ); } } const mapStateToProps = state => ({ - isComplete: state.serviceReducer.serviceMethodExecution.isComplete, + isServiceExecutionComplete: state.serviceReducer.serviceMethodExecution.isComplete, + freeCallsRemaining: state.serviceDetailsReducer.freeCallsRemaining, + freeCallsAllowed: state.serviceDetailsReducer.freeCallsAllowed, + email: state.userReducer.email, +}); + +const mapDispatchToProps = dispatch => ({ + fetchMeteringData: args => dispatch(serviceDetailsActions.fetchMeteringData({ ...args })), }); -export default connect(mapStateToProps)(withStyles(useStyles)(ServiceDemo)); +export default connect( + mapStateToProps, + mapDispatchToProps +)(withStyles(useStyles)(ServiceDemo)); diff --git a/src/components/ServiceDetails/index.js b/src/components/ServiceDetails/index.js index f18866dd0..58b397f2a 100644 --- a/src/components/ServiceDetails/index.js +++ b/src/components/ServiceDetails/index.js @@ -9,8 +9,9 @@ import StyledTabs from "./StyledTabs"; import AboutService from "./AboutService"; import InstallAndRunService from "./InstallAndRunService"; import { useStyles } from "./styles"; -import { serviceActions } from "../../Redux/actionCreators"; +import { serviceActions, serviceDetailsActions } from "../../Redux/actionCreators"; import { serviceDetails } from "../../Redux/reducers/ServiceReducer"; +import { generateFilterObject } from "../../utility/constants/Pagination"; class ServiceDetails extends Component { state = { @@ -22,12 +23,11 @@ class ServiceDetails extends Component { } fetchServices = () => { - const { service, pagination, fetchServices } = this.props; - if (service) { - return; - } - - fetchServices(pagination); + const { pagination, fetchServices, fetchServiceMetadata, match } = this.props; + const { orgId, serviceId } = match.params; + const filterData = generateFilterObject({ org_id: [orgId], service_id: [serviceId] }); + fetchServiceMetadata({ orgId, serviceId }); + fetchServices(pagination, filterData); }; handleTabChange = activeTab => { @@ -44,7 +44,11 @@ class ServiceDetails extends Component { const { activeTab } = this.state; const tabs = [ - { name: "About", activeIndex: 0, component: }, + { + name: "About", + activeIndex: 0, + component: , + }, { name: "Install and Run", activeIndex: 1, component: }, ]; @@ -54,8 +58,8 @@ class ServiceDetails extends Component { org_id={service.org_id} display_name={service.display_name} img_url={JSON.parse(service.assets_url).hero_image} - star_rating={service.service_rating} - totalRating={service.total_users_rated} + star_rating={service.service_rating ? JSON.parse(service.service_rating).rating : 0} + totalRating={service.service_rating ? JSON.parse(service.service_rating).total_users_rated : 0} /> @@ -65,12 +69,13 @@ class ServiceDetails extends Component { } const mapStateToProps = (state, ownProps) => ({ - service: serviceDetails(state, ownProps.match.params.service_row_id), + service: serviceDetails(state, ownProps.match.params), pagination: state.serviceReducer.pagination, }); const mapDispatchToProps = dispatch => ({ - fetchServices: pagination => dispatch(serviceActions.fetchService(pagination)), + fetchServiceMetadata: args => dispatch(serviceDetailsActions.fetchServiceMetadata({ ...args })), + fetchServices: (pagination, filterData) => dispatch(serviceActions.fetchService(pagination, filterData)), }); export default connect( diff --git a/src/components/UserProfile/UserProfileAccount/index.js b/src/components/UserProfile/UserProfileAccount/index.js new file mode 100644 index 000000000..beb9c8a20 --- /dev/null +++ b/src/components/UserProfile/UserProfileAccount/index.js @@ -0,0 +1,23 @@ +import React from "react"; +import Grid from "@material-ui/core/Grid"; +import { withStyles } from "@material-ui/styles"; +import Divider from "@material-ui/core/Divider"; +import StyledDropdown from "../../common/StyledDropdown"; + +import { useStyles } from "./styles"; + +const UserProfileAccount = ({ classes }) => { + return ( +
    + + +

    Payment / Transfer Method

    + + +
    +
    +
    + ); +}; + +export default withStyles(useStyles)(UserProfileAccount); diff --git a/src/components/UserProfile/UserProfileAccount/styles.js b/src/components/UserProfile/UserProfileAccount/styles.js new file mode 100644 index 000000000..c054a6b19 --- /dev/null +++ b/src/components/UserProfile/UserProfileAccount/styles.js @@ -0,0 +1,11 @@ +export const useStyles = theme => ({ + accountMainContainer: { + margin: "10px 0 50px", + }, + accountContainer: { + margin: "30px 0 50px", + borderRadius: 4, + backgroundColor: theme.palette.text.white, + boxShadow: "0 1px 1px 0 rgba(0,0,0,0.07), 0 2px 1px -1px rgba(0,0,0,0.07), 0 1px 3px 0 rgba(0,0,0,0.1)", + }, +}); diff --git a/src/components/UserProfile/UserProfileSettings/ConfirmDelete/index.js b/src/components/UserProfile/UserProfileSettings/ConfirmDelete/index.js index 4cc18195d..9f07e17ed 100644 --- a/src/components/UserProfile/UserProfileSettings/ConfirmDelete/index.js +++ b/src/components/UserProfile/UserProfileSettings/ConfirmDelete/index.js @@ -42,7 +42,7 @@ const ConfirmDelete = ({ open, handleClose, handleSubmit, error }) => {

    Are you sure?

    Deleting your account will go in affect immediately and you will not longer have access to your account - data.{" "} + data.

    Before you go...

    diff --git a/src/components/UserProfile/index.js b/src/components/UserProfile/index.js index 3d021a0b3..f3c599409 100644 --- a/src/components/UserProfile/index.js +++ b/src/components/UserProfile/index.js @@ -8,6 +8,7 @@ import { connect } from "react-redux"; import UserProfileSettings from "./UserProfileSettings"; import UserProfileHeader from "./UserProfileHeader"; import { useStyles } from "./styles"; +import UserProfileAccount from "./UserProfileAccount"; class UserProfile extends Component { state = { @@ -22,7 +23,10 @@ class UserProfile extends Component { const { classes, history, username } = this.props; const { activeTab } = this.state; - const tabs = [{ name: "Settings", activeIndex: 0, component: }]; + const tabs = [ + { name: "Account", activeIndex: 0, component: }, + { name: "Settings", activeIndex: 1, component: }, + ]; const activeComponent = tabs.filter(el => el.activeIndex === activeTab)[0].component; return (
    diff --git a/src/components/common/AlertBox/AlertLink.js b/src/components/common/AlertBox/AlertLink.js new file mode 100644 index 000000000..1e0697ba1 --- /dev/null +++ b/src/components/common/AlertBox/AlertLink.js @@ -0,0 +1,14 @@ +import React from "react"; + +const AlertLink = ({ link }) => { + if (link) { + return ( + + {link} + + ); + } + return null; +}; + +export default AlertLink; diff --git a/src/components/common/AlertBox/index.js b/src/components/common/AlertBox/index.js index be128f1a1..830b85627 100644 --- a/src/components/common/AlertBox/index.js +++ b/src/components/common/AlertBox/index.js @@ -4,22 +4,29 @@ import PropTypes from "prop-types"; import { withStyles } from "@material-ui/styles"; import { useStyles } from "./styles"; +import AlertLink from "./AlertLink"; export const alertTypes = { ERROR: "error", SUCCESS: "success", WARNING: "warning", + INFO: "info", }; const backgroundColor = { error: alertTypes.ERROR, success: alertTypes.SUCCESS, warning: alertTypes.WARNING, + info: alertTypes.INFO, }; -const AlertBox = ({ classes, message, type }) => { +const AlertBox = ({ classes, message, type, link }) => { if (message) { - return

    {message}

    ; + return ( +

    + {message} +

    + ); } return null; }; diff --git a/src/components/common/AlertBox/styles.js b/src/components/common/AlertBox/styles.js index 0bfbddcc7..33da893ba 100644 --- a/src/components/common/AlertBox/styles.js +++ b/src/components/common/AlertBox/styles.js @@ -23,5 +23,17 @@ export const useStyles = theme => ({ warning: { borderColor: theme.palette.text.warningBoxBorder, backgroundColor: theme.palette.text.warningBoxBg, + "& a": { + color: theme.palette.text.infoBoxLink, + fontWeight: 600, + }, + }, + info: { + borderColor: theme.palette.text.primary, + backgroundColor: theme.palette.text.infoBoxBg, + "& a": { + color: theme.palette.text.infoBoxLink, + fontWeight: 600, + }, }, }); diff --git a/src/components/common/Header/HeaderActions.js b/src/components/common/Header/HeaderActions.js index 367d1f58e..d12c5542a 100644 --- a/src/components/common/Header/HeaderActions.js +++ b/src/components/common/Header/HeaderActions.js @@ -27,7 +27,6 @@ const HeaderActions = ({ isLoggedIn, history }) => { className={`${classes.loginBtnsAnchor} ${classes.UppercaseText} ${classes.signupBtnText}`} onClick={() => handleRedirection(`/${Routes.SIGNUP}`)} > - {" "} Sign Up Free
  • diff --git a/src/components/common/StyledDropdown/index.js b/src/components/common/StyledDropdown/index.js index ca263d38f..8a0257543 100644 --- a/src/components/common/StyledDropdown/index.js +++ b/src/components/common/StyledDropdown/index.js @@ -5,12 +5,18 @@ import PropTypes from "prop-types"; import { useStyles } from "./styles"; -const StyledDropdown = ({ labelTxt, list, value, onChange }) => { +const StyledDropdown = ({ labelTxt, list, value, onChange, formControlProps, nativeSelectProps }) => { const classes = useStyles(); return ( - - + + {list.map(item => (