Configure Multiple Web store on (Live)

Check list need to get from customer side

1)Webshop ID 

2)Webshop URL (Live)

3)ERP webservice URL + credentials in case different from current one (beta and live)

4)Admin e-mail address of the live web shop URL (in order for the SSL certificate to be ordered by Sana hosting) 

email should have the following format.


double check user already maped the server details form their side 

 Verify whether url pointed to our server

Hi xxx, 

Thanks for the information,

It seems the live URL (www.wahlnl.store) is not mapped with our server,

could you please map the DNS of live URL to our server IP: <This is hosted ip 51.5.145.193.>

--------------------
eg wahl-beta.sanastores.net
 if u dont know the IP address , just log to server by RDP, and on brower type "whats my ip" 


1.Request license if not already created

Refer to the Configure Multiple Web store on (Beta) for more details


2.Request Certificate for the new webshop 

https://sanacommerce.visualstudio.com/Sana%20Hosting/_dashboards/dashboard/8dc80a0e-5113-49a4-bc3b-d813559d7d73

created ticket for New SSL Certificate for Champion Power Equipment.

https://sanacommerce.visualstudio.com/Sana%20Hosting/_workitems/edit/77686?src=WorkItemMention&src-action=artifact_link


Ravensburger CH: https://sanacommerce.visualstudio.com/Sana%20Hosting/_workitems/edit/107575


3. Create a new webshop 

eg: ChampionPowerCALive

 When you created a new webshop it required to have an NT popup because the site needs to be tested before granting access to the public users. (to Show NT popup Anonymous Authentication need to be Disabled).

 When we want to add a new webshop to Live, we do not directly bind the website URL to exist Live Web site (as we do in Beta sites).  we create the new webshop separately.


1.Authentication
2. Current Live Website

3.Newly created web site for With NT Popup



because IIS only provides one Authentication configuration (NT Popup) per site. (it does not support multiple NT Popup even we bind to different hostnames for one web site)

if the current shop is already on Live, Then its Anonymous Authentication is Enabled (NT popup is been disabled ).

As a solution for this, we create a new Webshop on IIS (ChampionPowerCALive) and set it's NT popup Enabled. to enable the NT Popup, we set as following (Image: 3.Newly created web site for With NT Popup)

Anonymous Authentication - Disable 

Basic Auth - Enabled.


 4. Add new licenses to the Live environment.

 add to bin folder/ backup old and 

Task service folder.


5. Select new SSL certificate

right click your Live site > site Binding > Edit > SSL certificate > select the correct / new license file.

 




if the certificate not installed correctly, it will show as following 








6. Run the script and add new web store to live > restart a pool





7. Need to change the app pool of the newly created site

for this example, we set  "ChampionPowerCALive" to the Original Live site app pool.

web site ChampionPowerLive and ChampionPowerCALive both use ChampionPowerLive app pool

else it will get an error on the new webshop.




8. Then go to the new webshop and the popup need to be displayed.

 



9.Bind after testing

after testing, we don't need an additional webshop with NT popup,

then add domain url of additional shop to live bindings


if You recive run time error 

add domain default shop 






created ticket for New SSL Certificate for Champion Power Equipment.

https://sanacommerce.visualstudio.com/Sana%20Hosting/_workitems/edit/77686?src=WorkItemMention&src-action=artifact_link

video call by Aji

https://photos.google.com/photo/AF1QipMjrVXN7aQlGjQ5FIbAyFXtSC1jpsuDUbv3ROF-


10. Check new Webshop name has been configured from the ERP side. by run Test connection.

else inform to customer. 

eg:

Hi XXXX, 

We have successfully created a new beta shop (SanaStoreCA). It seems the new webshop has not been configured from the ERP side.

Can you please check on this issue. 

















Configure Multiple Web store on (Beta)

 Configure Multiple Web store.

call record for the issue:-

https://web.microsoftstream.com/video/8c7e57cd-2811-419d-8ed6-c95313da18a0

more :

https://help.sana-commerce.com/sana-commerce-93/how_tos/multiple_domains_and_websites/configure_multiple_websites

--------------------------------------------------------------------------------------------------------

This will help you to configure a new webshop on the existing project.

for this example, I will use championpower project.

//need to have the following details shared by the Customer/Project Lead,

To Configure the webshop basically, we need the following details.

1. Website Id, 2. Web site Name, 3.Domain(URL). 

if  Project Lead request to create a domain URL as a placeholder like normal sana store domains,

Follow these steps.   

1 Create a new beta URL with the current beta URL,(If new URL not provided)

current webshop URL: https://championpower-beta.sanastores.net/

new webshop URL: https://championpower-ca-beta.sanastores.net/


* updated  license before running the script else current webshop also will get an error (regarding license)  section 4


2. If you create a new webshop URL you need to map it on the server.

* Create an Azure DevOps ticket and request to map the new URL to the server.

Ticket as following, 

https://sanacommerce.visualstudio.com/Sana%20Hosting/_workitems/edit/76731

Ravensburg AG shop: https://sanacommerce.visualstudio.com/Sana%20Hosting/_workitems/edit/106763

Ravensburg [FR] shop:https://sanacommerce.visualstudio.com/Sana%20Hosting/_workitems/edit/115431

Divercy CZ:  https://sanacommerce.visualstudio.com/Sana%20Hosting/_workitems/edit/108398

Please create a URL as following and map that URL to (your Projects server) 

URL: https://championpower-ca-beta.sanastores.net/

server IP: 40.118.191.64 can find from the Start site password section

https://start.intranet.sana-commerce.com/Pages/Project/PasswordList.aspx


* for some Projects Beta DNS Map need to be done by the Customer side,

eg Diversey, 

 [Diversey] Additional store Czech Republic /Sent: Wednesday, April 7, 2021 12:03 PM

Hi Angelique, 

Thanks for the information,

It seems the beta URL (test-eshopcz.diversey.com) is not mapped with server,

could you please map the DNS of web shop URL to server IP: 104.211.44.132.

 ----------------------------------------------------------------------


Verify whether url pointed to our server


3. Request new Licence for webshop

Go to Sana community and navigate to the License page: 

https://community.sana-commerce.com/MySana/Licensepage.aspx

search the project and open the latest License in a separate tab. (last updated License )

create a new license and copy all the details from the last updated License.

update the Amount of webstores 

 Webstore domains sections:  add new beta and live URLs 

eg: 

old license Amount of webstores: 1

new  license Amount of webstores: 2

 


* Check the newly created license details with senior team members.
* After license creation need to get approval from the Project Manager

* After approving the license, go to Beta RDP ,keep a backup of the current license, and replace it with the new license.

* * Add to Task service folder also.

* Make sure the beta site is Still working without any issue.

some projects create separate licenses for Live and beta.

double-check the comma-separated when add to web store domains.

after approval double-checks the license file open by right click and edit. all URLs are currently separated.


4. * If the license is updated only run the script else current webshop also will get an error (regarding license) 



5 Run the script

NewWebsiteID: SanaStoreCA

New Website Name: SanaStoreCA

Domain: https://championpower-ca-beta.sanastores.net/


6. Go to IIS> Bind the new URL to the Beta site

after the refresh app pool you will see the newly created web store on the dev/beta admin section.

open the new site link, it should open.



if you do not bind the URLs yet, you will get this error



add existing SSL certificate to Https bindings..


if the certificate not installed correctly, it will show as following 





7. Update ERP connections details.

when you try to run indexes if getting any errors from ERP then need to check the test connection.


8. Check new Webshop name has been configured from the ERP side. by run Test connection.

else inform to customer. 

mail : RE: [Ravensburger] CH new shop not been configured from the ERP side.

eg:

Hi XXXX, 

We have successfully created a new beta shop (SanaStoreCA). It seems the new webshop has not been configured from the ERP side.

Can you please check on this issue. 


Maintanese mode is activate: issue from ERP side 


some times when u trys to run idexes its not loaded 

to solve stop and restart the task service


 



-----------------------------------------------------------------------------------------





create react app

 open Vs code 

go to the specific folder 

cd 

cd /d/Tutorials/YourfolderName

> npm install

 > create-react-app react-hook

Then install the necessary items and create the project

To run the project need to Go to the Project folder 

>cd react-hook

start Project

> npm start

Then it will start the project. 


Short cut for 

imrImport React
imrcImport React / Component
imrsImport React / useState

ccClass Component
cccClass Component With Constructor
cpcClass Pure Component

usestate for create : const [shouldCount, setshouldCount] = useState(initialState)

Project : D:\Tutorials\React\ReatHooks

https://web.microsoftstream.com/video/9873ef9d-3246-4cdd-a482-fbab3d4dda14

Class vs Function Componentes.

ClassCounter.js

import React from "react";

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      color: "red",
    };
  }

  handleClick = () => {
    this.setState(({ count }) => ({
      count: count + 1,
    }));
  };

  handleColorChange = () => {
    if (this.state.color === "red") this.setState({ color: "green" });
    else this.setState({ color: "red" });
  };

  render() {
    return (
      <>
        <h1 style={{ color: this.state.color }}>The count is {this.state.count}</h1>
        <button onClick={this.handleClick}>Increase</button>
        <button onClick={this.handleColorChange}>Togle color</button>
      </>
    );
  }
}

export default Counter;

Counter.js

import React, { useState, useEffect } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  const handleClick = () => setCount(count + 1);

  const [color, setColor] = useState("red");
  const handleColorChange = () => {
    if (color === "red") setColor("green");
    else setColor("red");
  };

  useEffect(() => {
    document.title = count;
  }, []);

  return (
    <>
      <h1 style={{ color }}>Functional Counter ,Count is : {count}</h1>
      <button onClick={handleClick}>Increase</button>
      <button onClick={handleColorChange}>Togle color</button>
    </>
  );
useEffect
}


Life cycle methods exsisting for right to perform SIDE Effects 

 for class have 3  

1. componentDidMount()

2. componentDidUpdate()

3. componentWillUnmount()  

componentDidMount() {
    document.title = this.state.count;
    this.interval = setInterval(() => console.log(new Date().toLocaleTimeString()), 500);
  }

  componentDidUpdate() {
    document.title = this.state.count;
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

for Function have only one 

1.useEffect

useEffect(() => {
    document.title = count;
  }, []);

  useEffect(() => {
    const interval = setInterval(() => console.log(new Date().toLocaleTimeString()), 500);
    return () => clearInterval(interval);
  }, []);


React hook can not create inside if codition it will give Error

TotalCounter.js

import React, { useEffect } from "react";

export default function TotalCount({ value }) {
  if (value !== 0) {
    useEffect(() => {
      document.title = "Item in basket: " + value;
    });
  }
  return <h1> The totalcount is {value}</h1>;
}

on App.js 
 return <TotalCount />;

it will give following error
./src/hooks/TotalCounter.js
Line 5:5: React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render react-hooks/rules-of-hooks


correct way is following use condition inside the useEffect 

import React, { useEffect } from "react";

export default function TotalCount({ value }) {
  useEffect(() => {
    if (value !== 0) {
      document.title = "Item in basket: " + value;
    }
  });

  return <h1> The totalcount is {value}</h1>;
}

Then title only update for value != 0

eg : value = 0 // not show title on page

eg: value =5 // show on Title.


You can write Effects inside the functions to,

when create funtions always set name as : useDocumentTitle

 TotalCounter.js

import React, { useEffect } from "react";

export default function TotalCount({ value }) {
  
  useDocumentTitle("Item in basket:- " + value);
  return <h1> The totalcount is {value}</h1>;
}

function useDocumentTitle(title) {
  useEffect(() => {
    document.title = title;
  });
}


End of React hooks video 


React list and keys https://web.microsoftstream.com/video/893c1c4f-5f1d-4f7a-baba-bfbee546dbfb

Event Handles optimization

Basket.js

import React, { useState } from "react";
import FancyButton from "./FancyButton";

export default function Basket() {
  const [totalCount, setTotalCount] = useState(0);
  const handleChange = (e) => {
    if (e.target.value === "i") setTotalCount(totalCount + 1);
    else setTotalCount(totalCount - 1);
  };

  const [color, setColor] = useState("red");
  const handleColorToggle = () => {
    if (color === "red") setColor("green");
    else setColor("red");
  };

  return (
    <>
      <h1 style={{ color }}>Total count is {totalCount}</h1>
      <FancyButton value="i" onClick={handleChange} text="Increase"></FancyButton>
      <FancyButton value="d" onClick={handleChange} text="Increase"></FancyButton>
      <FancyButton onClick={handleColorToggle} text="Togle color"></FancyButton>
    </>
  );
}

FancyButton.js

import React from "react";

function FancyButton({ text, onClick, ...atributes }) {
  console.count(text);
  return (
    <button onClick={onClick} {...atributes}>
      {text}
    </button>
  );
}
export default React.memo(FancyButton);

App.js

return <Basket />;



Hooks

its called useCallback()

 import React, { useState, useCallback } from "react";

import FancyButton from "./FancyButton";

export default function Basket() {
  const [totalCount, setTotalCount] = useState(0);
  const handleChange = (e) => {
    if (e.target.value === "i") setTotalCount(totalCount + 1);
    else setTotalCount(totalCount - 1);
  };

  const [color, setColor] = useState("red");
  const handleColorToggle = useCallback(() => { // <--- useCallback()
    if (color === "red") setColor("green");
    else setColor("red");
  }, [color]); // <--- add aditinal parameter .

  return (
    <>
      <h1 style={{ color }}>Total count is {totalCount}</h1>
      <FancyButton value="i" onClick={handleChange} text="Increase"></FancyButton>
      <FancyButton value="d" onClick={handleChange} text="Decrease"></FancyButton>
      <FancyButton onClick={handleColorToggle} text="Togle color"></FancyButton>
    </>
  );
}


List and Keys  video 13.00

video : https://web.microsoftstream.com/video/893c1c4f-5f1d-4f7a-baba-bfbee546dbfb

List.js

import React from "react";

export default function List() {
  return [1, 2, 3, 4, 5, 6];
}

App.js

return <List />;


Render elements inside Array

export default function List() {
  return [1, 2, 3, 4, 5, 6].map((number) => {
    return <b>{number}</b>;
  });
}

or can embded map into JSX

List.js

import React from "react";

// export default function List() {
//   return [1, 2, 3, 4, 5, 6].map((number) => {
//     return <b>{number}</b>;
//   });
// }

export default function List({ numbers }) {
  return (
    <ul>
      {numbers.map((number) => {
        return <li>{number}</li>;
      })}
    </ul>
  );
}

App.js

function App() {  
  return <List numbers={[1, 2, 3, 4, 5]} />;
}

Warning: Each child in a list should have a unique "key" prop.

Check the render method of `List`. See https://fb.me/react-warning-keys for more information.

    in li (at List.js:13)

    in List (at App.js:13)

    in App (at src/index.js:9)

    in StrictMode (at src/index.js:8)

need to Give an index for list 

App.js

export default function List({ numbers }) {
  return (
    <ul>
      {numbers.map((number, index) => {
        return <li key={index}>{number}</li>;
      })}
    </ul>
  );
}


List.js

const initialProducts = [
  { id: "one", title: "One" },
  { id: "two", title: "Two" },
];

const updatedProducts = [{ id: "three", title: "Three" }, ...initialProducts];

export default function List() {
  const [products, setProducts] = useState(initialProducts);

  useEffect(() => {
    setTimeout(() => setProducts(updatedProducts), 5000);
  }, []);

  return (
    <ul>
      {products.map((product, index) => {
        return <li key={index}>{product.title}</li>;
      })}
    </ul>
  );
}

App.js

return <List />;

 Display output 

  • Three // This will load after 5 second
  • One
  • Two


-----------------------------------------------------------

Video

React part III (Eng) 

https://web.microsoftstream.com/video/fbdc7b4e-39ac-472a-9502-ff99c2f2e7ea

FlexiPage.js

import React from "react";
import PropTypes from "prop-types";

function FlexiPage({ title }) {
  return <h1>{title}</h1>;
}

FlexiPage.propTypes = {
  title: PropTypes.string,
};

export default FlexiPage;

App.js

<FlexiPage title={2} />


Counter.js

import React, { useState } from "react";
import App from "./App";

const Counter = ({ renderTitle }) => {
  const [count, setCount] = useState(0);
  const handleIncrease = () => setCount(count + 1);

  return (
    <>
      <p>{renderTitle(count)}</p>
      <button onClick={handleIncrease}>Increase</button>
    </>
  );
};

export default Counter;

App.js

<Counter renderTitle={(count) => <li>italic{count}</li>} />


Make Prop optinal

in case if we not passiing a value to props

Counter.js

 {!renderTitle && <p>Default title {count}</p>} // defauls
 {renderTitle && <p>{renderTitle(count)}</p>}

App.js

<Counter />

out Put:

2

Default title 0


Rendering External Content

Add content as extra paramenter,

Counter.js

const Counter = ({ renderTitle, content }) => {
  const [count, setCount] = useState(0);
  const handleIncrease = () => setCount(count + 1);
  return (
    <>
      {!renderTitle && <p>Default title {count}</p>}
      {renderTitle && <p>{renderTitle(count)}</p>}
      {content}
      <button onClick={handleIncrease}>Increase</button>
    </>
  );
};

App.js

 <Counter
        renderTitle={(count) => <li>italic{count}</li>}
        content="This is a content of our counter."
      />

outPut:

2

  • italic4
  • This is a content of our counter.

    ---------------------------------------------------------------------

    You can render Flexi Page inside counter compornent

    App.js

    <Counter
            renderTitle={(count) => <li>italic{count}</li>}
            content={<FlexiPage title="Inner flexi Page" />}
          />

    2

  • italic2
  • Inner flexi Page


    Pass compornent as Props  Video43.38

    App.js
    <Counter
            renderTitle={(count) => <li>italic{count}</li>}
            content={<FlexiPage title="Inner flexi Page" />}
            component={FlexiPage}
          />

    Counter.js
    const Counter = ({ renderTitle, content, component: Component }) => {
      const [count, setCount] = useState(0);
      const handleIncrease = () => setCount(count + 1);

      return (
        <>
          {!renderTitle && <p>Default title {count}</p>}
          {renderTitle && <p>{renderTitle(count)}</p>}
          {content}
          <Component title="Flexi page passed as component type." />
          <button onClick={handleIncrease}>Increase</button>
        </>
      );
    };

    o/p

    2

  • italic0
  • Inner flexi Page

    Flexi page passed as component type.


    HOC video 46.55

    ----------------------------------------------------------------------------------------------------------------------

    Redux Knowledge Sharing Session 8 - Redux #1

    Main Elements

    1.Store

    2Action

    3.Reducer


    Action

    how it looks like general

    export const ADD_PRODUCT = 'ADD_PRODUCT';
    const addProductAction = {
    type: ADD_PRODUCT,
    id: 'productID'
    ,
    };

    In Project Jupiter we have only two properties

    type and payload

    export const ADD_PRODUCT = 'ADD_PRODUCT'; <-- use capital
    const addProductAction = {
    type: ADD_PRODUCT,
    payload: { id: 'productID' },<-- This is object can add any value
    };


    Reducer

    Specifies how the application's state changes in response to actions sent to the store.

    import { SANATEXTS_LOADED } from "./actions"; //import action types

    const initialState = {};

    //first time reducer will be called with 'undefined' for state argument
    //so it is the place where to initialize default state.
    //Redux expects it not to be 'undefined'
    export default function (state = initialState, action) {
      if (action.type === SANATEXTS_LOADED)
        // handle specific action
        return { ...state, ...action.payload }; // return completely new state
    }


    store

    Holds application state.
    Allows access to state via getState()
    Allows state update via dispatch(action)
    Registers listeners via subscribe(listener)


    CREATING STORE

    import { createStore } from 'redux';
    import rootReducer from './reducer';
    const store = createStore(rootReducer, window.STATE_FROM_SER


    Dispatch

    store.dispatch(increment());


    ACTION CREATORS 

    Action creators are exactly that — functions that create actions.

    export const SANATEXTS_REQUESTED = 'SANATEXTS_REQUESTED';
    export const loadSanaTexts = keys => ({
    type: SANATEXTS_REQUESTED,
    payload: { keys },
    });


    On Demo video time 22.21

    index.js

    install redux to our project  npm i redux

    .....
    import { createStore } from "redux"; //<-- import createStore form redux

    // 2. Create action
    const INCREMENT = "INCREMENT";
    const increment = () => ({
      type: INCREMENT,
    });

    // 3. Create reducer
    const initialState = { count: 0 };
    function rootReducer(state = initialState, action) {
      if (action.type === INCREMENT) return { count: state.count + 1 };

      return state;
    }

    // 1. create store
    const store = createStore(rootReducer);
    store.subscribe(() => console.log(store.getState()));

    //Dispatch
    store.dispatch(increment());
    ...

    when do it correctly

    index.js

    import App from "./App";
    import reportWebVitals from "./reportWebVitals";
    import { createStore } from "redux"; //<-- import createStore form redux
    import { rootReducer } from "./behavior/reducer";

    // 2. Create action >use seperate file to
    // 3. Create reducer 
    // 1. create store
    const store = createStore(rootReducer);

    ReactDOM.render(
      <React.StrictMode>
        <App store={store} />
      </React.StrictMode>,
      document.getElementById("root"),
    );

    reportWebVitals();

    behavior/action.js

    // 2. Create action
    export const INCREMENT = "INCREMENT";
    export const increment = () => ({
      type: INCREMENT,
    });

    export const DECREMENT = "DECREMENT";
    export const decrement = () => ({
      type: DECREMENT,
    });

    behavior/reducer.js

    import { INCREMENT, DECREMENT } from "./action";

    // 3. Create reducer
    const initialState = { count: 0 };
    export function rootReducer(state = initialState, action) {
      if (action.type === INCREMENT) return { count: state.count + 1 };
      if (action.type === DECREMENT) return { count: state.count - 1 };
      return state;
    }

    Counter.js

    import { React } from "react";
    import { increment, decrement } from "./behavior/action";

    const Counter = ({ count, dispatch }) => {
      const onIncrement = () => dispatch(increment());
      const onDecrement = () => dispatch(decrement());

      return (
        <>
          <h1>{count}</h1>
          <button onClick={onIncrement}>Increment</button>
          <button onClick={onDecrement}>Decrement</button>
        </>
      );
    };
    export default Counter;

    App.js

    import Counter from "./Counter";
    import { useState, useEffect } from "react";

    function App({ store }) {
      const [appState, setAppState] = useState(store.getState());

      useEffect(() => {
        store.subscribe(() => {
          setAppState(store.getState());
        });
      }, [store]);

      return (
        <div className="App">
          <Counter count={store.getState().count} dispatch={store.dispatch} />
        </div>
      );
    }