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, { useStateuseEffect } from "react";

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

  const [colorsetColor] = 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 [totalCountsetTotalCount] = useState(0);
  const handleChange = (e=> {
    if (e.target.value === "i"setTotalCount(totalCount + 1);
    else setTotalCount(totalCount - 1);
  };

  const [colorsetColor] = 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({ textonClick, ...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, { useStateuseCallback } from "react";

import FancyButton from "./FancyButton";

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

  const [colorsetColor] = 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 [123456];
}

App.js

return <List />;


Render elements inside Array

export default function List() {
  return [123456].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={[12345]} />;
}

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((numberindex=> {
        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 [productssetProducts] = useState(initialProducts);

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

  return (
    <ul>
      {products.map((productindex=> {
        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 [countsetCount] = 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 = ({ renderTitlecontent }) => {
  const [countsetCount] = 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 = ({ renderTitlecontentcomponent: Component }) => {
      const [countsetCount] = 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 = initialStateaction) {
      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(rootReducerwindow.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 = initialStateaction) {
      if (action.type === INCREMENTreturn { 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 { INCREMENTDECREMENT } from "./action";

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

    Counter.js

    import { React } from "react";
    import { incrementdecrement } from "./behavior/action";

    const Counter = ({ countdispatch }) => {
      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 { useStateuseEffect } from "react";

    function App({ store }) {
      const [appStatesetAppState] = useState(store.getState());

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

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


















    Configure Multiple Web store (DEV)

    Add web store to existing shop (DEV) 

    1. Add web store by script

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


    SET @newWebsiteId = N'SANASTORENZ'; -- set a new website ID instead of 'NewWebsiteID'
    SET @newWebsiteName = N'NZ STORE'; -- set the name of the new website instead of 'New Website Name'
    SET @newWebsiteDomain = N'integriah-dev-nz.corp.ism.nl'; -- set the domain for new website instead of 'localhost'
    SELECT @defaultLanguage = Id FROM [Languages] WHERE [IsDefault] = 1;

    make sure your domain looks line following (match with license file domains)

    eg: integriah-dev-nz.corp.ism.nl

     <string>*.corp.ism.nl</string>
     <string>localhost</string>
     <string>*.local</string>



    2. Add license. 
    you may need to add the license file. but no need to request a new one,
    you can use the existing one using for Multiple webshop related projects 

    Eg: Divercy  Project
    you will find it from the Bin folder

    sanaprojects_dev.license 

    else it will give an invalid Licence error.










     

    3. Add Web site to IIS

    Site > Add Website




    4. Add binding to IIS

    right-click Web site > Edit Bindings




     5.Update host file
        C:\Windows\System32\drivers\etc\host

    127.0.0.1 integriah-dev-nz.corp.ism.nl
    127.0.0.1 integriah-dev.corp.ism.nl


    6.Update Visual Studio Server settings



    6.1 right click your Project Startersite > Properties >select Web tab 
    Go to server section > Change to Local IIS >
    update Project URL with Sana store url

    if the current sanastore URL is localhost give the main domain name for it 
    eg  localhost  --> integriah-dev.corp.ism.nl






    6.Update ERP connections



    Errors found 



    to fix : update Web.config
    <httpCookies httpOnlyCookies="true"requireSSL="true"sameSite="None"/>
    change this one to
    <httpCookies httpOnlyCookies="true"/>


    ----------------------------------------------------------------------------------------------------
    begin transaction

    DECLARE @newWebsiteId nvarchar(50);
    DECLARE @newWebsiteName nvarchar(50);
    DECLARE @newWebsiteDomain nvarchar(50);
    DECLARE @defaultLanguage int;
    DECLARE @homePageId nvarchar(max);
    DECLARE @customerServicePageId nvarchar(max);

    SET @newWebsiteId = N'NewWebsiteID'; -- set a new website ID instead of 'NewWebsiteID'
    SET @newWebsiteName = N'New Website Name'; -- set the name of the new website instead of 'New Website Name'
    SET @newWebsiteDomain = N'localhost'; -- set the domain for new website instead of 'localhost'
    SELECT @defaultLanguage = Id FROM [Languages] WHERE [IsDefault] = 1;

    -- basic website info
    INSERT INTO [Websites] ([Id], [Name], [DefaultLanguageId]) VALUES (@newWebsiteId, @newWebsiteName, @defaultLanguage);
    INSERT INTO [WebsiteLanguages] ([WebsiteId], [LanguageId]) VALUES (@newWebsiteId, @defaultLanguage);
    INSERT INTO [WebsiteDomains] ([Id], [WebsiteId], [Domain], [IsDefault]) VALUES (NEWID(), @newWebsiteId, @newWebsiteDomain, 1);
    UPDATE users SET Fields.modify('insert <string>{sql:variable("@newWebsiteId")}</string> into (//field[@name="Websites"]/ArrayOfString)[1]')
    FROM [AdminUsers] users JOIN [AdminUsersRoles] usersRoles ON users.Id = usersRoles.AdminUserId 
    WHERE usersRoles.AdminRoleId = 'FE0072B6-70AA-4C53-8716-1FD9515E4998' and users.Fields.exist('//field[@name="Websites"]/ArrayOfString/string[text()=sql:variable("@newWebsiteId")]') = 0;

    -- create Home page
    SET @homePageId = CAST(NewId() AS nvarchar(50)) 
    INSERT [dbo].[FlexiPages] ([Id], [WebsiteId], [Title], [CreatedDate], [ModifiedDate], [Fields], [Url]) VALUES (@homePageId, @newWebsiteId, N'Home', GETDATE(), GETDATE(), N'<FieldsDictionary><field name="MetaDescription" type="Null" /><field name="MetaTitle" type="Null" /><field name="Content" type="Sana.Commerce.Content.ContentBlockCollection, Sana.Commerce"><ContentBlocks><MainBanner><Id>1423653167815</Id><ImagePath>/content/files/images/Homepage-banner.jpg</ImagePath><Link /></MainBanner><Html><Id>87265895-2884-4A2F-92D4-EFE5239D0135</Id><Content>&lt;br&gt;This is a Flexi-page. On a Flexi page, you are free to use blocks of text and images, to make the pages look just the way you want them to look. You can easily change the images and text of the Flexi-pages in the “Web pages” section in the Sana Admin. You can also use the In-site editor to change the content of the webstore while looking at it.</Content></Html><ImageTiles><Id>68520105-5903-4D6D-9B72-666AF48435AF</Id><Tiles><ImageTile><ImagePath>/content/files/images/place holder 3.jpg</ImagePath><AltText>Block 1 image</AltText><Link /></ImageTile><ImageTile><ImagePath>/content/files/images/place holder 3.jpg</ImagePath><AltText>Block 2 image</AltText><Link /></ImageTile><ImageTile><ImagePath>/content/files/images/place holder 3.jpg</ImagePath><AltText>Block 3 image</AltText><Link /></ImageTile><ImageTile><Link /></ImageTile></Tiles></ImageTiles></ContentBlocks></field></FieldsDictionary>', N'home')

    -- create Customer service page
    SET @customerServicePageId = CAST(NewId() AS nvarchar(50))
    INSERT [dbo].[FlexiPages] ([Id], [WebsiteId], [Title], [CreatedDate], [ModifiedDate], [Fields], [Url]) VALUES (@customerServicePageId, @newWebsiteId, N'Customer service', GETDATE(), GETDATE(), N'<FieldsDictionary><field name="Content" type="Sana.Commerce.Content.ContentBlockCollection, Sana.Commerce"><ContentBlocks><Html><Content>&lt;h1&gt;Customer service&lt;/h1&gt;
    &lt;p&gt;&lt;br /&gt;
    &lt;/p&gt;
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis nibh neque, egestas et, aliquet a, fermentum at, nunc. In aliquam. Maecenas metus dui, laoreet in, euismod id, iaculis sit amet, felis. Suspendisse consectetuer odio nec est. Sed blandit mauris vel neque. Pellentesque at orci vitae elit iaculis imperdiet. Sed est turpis, blandit vitae, euismod eget, feugiat ac, arcu.&lt;br /&gt;
    Duis nisl. Etiam quam ligula, dapibus sed, faucibus eget, volutpat sed, est. Mauris quis sem. Donec iaculis dui fermentum eros. Pellentesque eget libero vitae sapien interdum ullamcorper. Aenean at nulla in velit tristique venenatis. Duis malesuada metus a dolor. Sed ante. Integer mi mi, sodales vitae, adipiscing a, luctus nec, diam.&lt;br /&gt;
    &amp;nbsp;&lt;br /&gt;
    Maecenas aliquam aliquet massa. Donec ut purus. Maecenas volutpat, ipsum at consectetuer pretium, urna lorem tempor mi, vitae pellentesque mauris felis eget lorem. Nam ut lectus quis sem placerat venenatis. Nam et nisi non magna pulvinar dignissim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam venenatis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus volutpat. Integer suscipit. Mauris egestas accumsan eros. Nunc et massa. Aliquam erat volutpat.
    &lt;div style="text-align: center;"&gt;&lt;/div&gt;
    &lt;p&gt;&lt;br /&gt;
    &lt;/p&gt;</Content><Id>0641C81A-ADDF-4A95-BFB8-6E4CC1793011</Id></Html></ContentBlocks></field></FieldsDictionary>', N'service')

    -- create General settings
    INSERT [dbo].[Settings] ([Fields], [WebsiteId], [Key], [CreatedDate], [ModifiedDate]) VALUES (N'<FieldsDictionary><field name="DefaultCurrency" type="System.String, mscorlib" storeWithEntity="False"><string>EUR</string></field><field name="DropdownVariants" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="CheckStock" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>false</boolean></field><field name="RedirectOnAddToBasket" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>false</boolean></field>
    <field name="ShowProgressIndicator" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="ShopEmailAddress" type="System.String, mscorlib" storeWithEntity="False"><string>scdemo@sana-commerce.com</string></field><field name="ShowOrderAmountInBasketMiniature" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>false</boolean></field><field name="ReferenceNoVisibility" type="System.String, mscorlib" storeWithEntity="False"><string>SalesAgentAndB2BCustomer</string></field><field name="OrderCommentsVisibility" type="System.String, mscorlib" storeWithEntity="False">
    <string>SalesAgentAndB2BCustomer</string></field><field name="AdministrationMailList" type="System.String, mscorlib" storeWithEntity="False"><string>scdemo@sana-commerce.com</string></field><field name="PlaceOrderType" type="System.String, mscorlib" storeWithEntity="False"><string>Order</string></field><field name="RequestedDeliveryDateVisibility" type="System.String, mscorlib" storeWithEntity="False"><string>SalesAgentAndB2BCustomer</string></field><field name="EnableNewsletterSubscription" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field>
    <field name="AnalyticsAccountId" type="System.String, mscorlib" storeWithEntity="False"><string /></field><field name="EnableActionPrices" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="EditOrder" type="System.String, mscorlib" storeWithEntity="False"><string>SalesAgentAndB2BCustomer</string></field><field name="EnableLastViewedProducts" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="CheckoutOfferings" type="System.String, mscorlib" storeWithEntity="False"><string /></field>
    <field name="ShowTellaFriend" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="ConfigurableShippingAddress" type="System.String, mscorlib" storeWithEntity="False"><string>SalesAgentAndB2BCustomer</string></field><field name="EnableWishList" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="EnableRatingsAndReviews" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="ShippingCostVatRateId" type="System.String, mscorlib" storeWithEntity="False">
    <string /></field><field name="PaymentCostVatRateId" type="System.String, mscorlib" storeWithEntity="False"><string /></field><field name="EnablePromotionCodes" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="ShopName" type="System.String, mscorlib" storeWithEntity="False"><string>Sana Store</string></field><field name="ShopPhoneNumber" type="System.String, mscorlib" storeWithEntity="False"><string>010-1112233</string></field><field name="FromEmailAddress" type="System.String, mscorlib" storeWithEntity="False"><string>scdemo@sana-commerce.com</string>
    </field><field name="BccEmailAddresses" type="System.String, mscorlib" storeWithEntity="False"><string /></field><field name="StockPresentation" type="System.String, mscorlib" storeWithEntity="False"><string>ShowIndicator</string></field><field name="HomePageUrl" type="Sana.Commerce.Web.Links.LinkData, Sana.Commerce" storeWithEntity="False"><LinkData><Type>FlexiPage</Type><InternalUrlData>' + @homePageId + '</InternalUrlData></LinkData></field><field name="EnableCreateProspect" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="ShowOrderShippingStatus" type="System.Boolean, mscorlib" storeWithEntity="False">
    <boolean>true</boolean></field><field name="MenuDropdownType" type="System.String, mscorlib" storeWithEntity="False"><string>Dropdown</string></field><field name="BreadcrumbVisible" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>true</boolean></field><field name="WebServiceEnabled" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>false</boolean></field><field name="ReorderVisibility" type="System.String, mscorlib" storeWithEntity="False"><string>All</string></field><field name="MobileProductSetsIds" type="System.Collections.Generic.List`1[[System.String, mscorlib]], mscorlib" storeWithEntity="False">
    <ArrayOfString /></field><field name="EstimatedShippingCosts" type="Sana.Commerce.Shop.CostInfoCollection, Sana.Commerce"><ArrayOfCostInfo /></field><field name="CustomerServicePage" type="Sana.Commerce.Web.Links.LinkData, Sana.Commerce" storeWithEntity="False"><LinkData><Type>FlexiPage</Type><InternalUrlData>' + @customerServicePageId + '</InternalUrlData></LinkData></field><field name="ClosedShop" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>false</boolean></field><field name="OrderConfirmationEmailBehavior" type="System.String, mscorlib" storeWithEntity="False"><string>AlwaysSend</string>
    </field><field name="EnableCustomersOrderMail" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>false</boolean></field><field name="SendMailToReportAddresses" type="System.Boolean, mscorlib" storeWithEntity="False"><boolean>false</boolean></field><field name="ReportAddresses" type="Null" storeWithEntity="False" /></FieldsDictionary>', @newWebsiteId, N'General', GETDATE(), GETDATE())

    -- create PageLayout settings
    INSERT [dbo].[Settings] ([Fields], [WebsiteId], [Key], [CreatedDate], [ModifiedDate]) VALUES (N'<FieldsDictionary><field name="B2CCustomer_ProductListPage" type="System.String, mscorlib" storeWithEntity="False"><string>List</string></field><field name="B2CCustomer_ProductDetailsPage" type="System.String, mscorlib" storeWithEntity="False"><string>DetailsB2C</string></field><field name="B2CCustomer_SearchResultPage" type="System.String, mscorlib" storeWithEntity="False"><string>Search</string></field><field name="B2CCustomer_BasketPage" type="System.String, mscorlib" storeWithEntity="False">
    <string>Consumer</string></field><field name="B2BCustomer_ProductListPage" type="System.String, mscorlib" storeWithEntity="False"><string>ListB2B</string></field><field name="B2BCustomer_ProductDetailsPage" type="System.String, mscorlib" storeWithEntity="False"><string>DetailsB2B</string></field><field name="B2BCustomer_SearchResultPage" type="System.String, mscorlib" storeWithEntity="False"><string>SearchB2B</string></field><field name="B2BCustomer_BasketPage" type="System.String, mscorlib" storeWithEntity="False"><string>Business</string></field>
    <field name="SalesAgent_ProductListPage" type="System.String, mscorlib" storeWithEntity="False"><string>ListB2B</string></field><field name="SalesAgent_ProductDetailsPage" type="System.String, mscorlib" storeWithEntity="False"><string>DetailsB2BWithMatrix</string></field><field name="SalesAgent_SearchResultPage" type="System.String, mscorlib" storeWithEntity="False"><string>Search</string></field><field name="SalesAgent_BasketPage" type="System.String, mscorlib" storeWithEntity="False"><string>Business</string></field>
    <field name="B2CCustomer_SearchResultsPage" type="System.String, mscorlib" storeWithEntity="False"><string>Search</string></field><field name="B2BCustomer_SearchResultsPage" type="System.String, mscorlib" storeWithEntity="False"><string>SearchB2B</string></field><field name="SalesAgent_SearchResultsPage" type="System.String, mscorlib" storeWithEntity="False"><string>SearchB2B</string></field></FieldsDictionary>', @newWebsiteId, N'PageLayout', GETDATE(), GETDATE())

    UPDATE [Settings] SET Fields.modify('replace value of (//field[@name="ShopName"]/string/text())[1] with sql:variable("@newWebsiteName")')
    WHERE [Key] = 'General' AND [WebsiteId] = @newWebsiteId;

    commit


    Image read from URL

    Project: Borsig

    --------------------------------- When using WebClient-------------------------------------------

    ExtendedImageLinkTask
    
    private Stream LoadProductImageStream(IProductImage image)
            {
                try
                {
                    using (WebClient webClient = new WebClient())
                    {
                        //  Download from Particular website expects a User-Agent header to be specified.                     
                        webClient.Headers["User-Agent"= "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)";
                        
                        var result = webClient.DownloadData(image.MediumImagePath);
                        Stream stream = new MemoryStream(result);
                        return stream;
                    }
                }
                catch (Exception ex)
                {
                    TaskLog.Current.Add(this"Error on image download" + ex.Message, LogPriority.Medium);
                }             
                return null;
            } 
        }


    --------------------------------- When use HttpClient -------------------------------------------

    using (HttpClient client = new HttpClient())
                {
                    var url = "http://www.te.com/content/dam/te-com/catalog/part/214/184/371/2-1418437-1-t1.jpg/jcr:content/renditions/product-high-res.png";
     
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));      //image/png
                    HttpResponseMessage response = client.GetAsync(url).Result;
     
                    if (response.IsSuccessStatusCode)
                    {
                        System.Net.Http.HttpContent content = response.Content;
                    }
                    else
                    {
                        throw new FileNotFoundException();
                    }
                }







    Configure Tag manager and Google Analytics

     configure Tag manager

    https://www.youtube.com/watch?v=UcJB3UKsFDo&feature=youtu.be


    create Analics Home > Admin > Create Account

    2

    copy id 

     

    3 create Tag manager 


    4 copy the GTM-XXX id and Past it on Sana Admin > setup> markeeting > Analitics 


    5 Go to Tag manager > Tags > create new > give name and tracking ID of Google Analitics eg :

     UA-175XXXXX


    6. Then Come to Sana Home And should show new Panel (Google Tag manager )









    Pass value by popup Ajax

     

    Project : Colruty_935
    control.ordertemplate.js




    Extended order template controller

    [HttpPost]
            public ActionResult SaveNewOrderTemplate(string name)
            {              
                var existingTemplates = ShopApi.OrderTemplates.GetTemplates();
                if (existingTemplates.Any(t => t.Name == name))
                { 
                    var orderTemplate_SaveFailedInUse = CommerceFrameworkBase.SanaTexts.GetSanaText("OrderTemplate_SaveFailedInUse");
                    return Json(new { id = 0, error= orderTemplate_SaveFailedInUse }, JsonRequestBehavior.AllowGet);//fail
                }
     
                ShopApi.OrderTemplates.SaveOrderTemplate(name); 
     
                // Get Template by name 
                var existingTemplates2 = ShopApi.OrderTemplates.GetTemplates();
                var template2 = existingTemplates2.Where(x => x.Name == name).FirstOrDefault();
                var tempId = template2.Id;
                //return Json(tempId, JsonRequestBehavior.AllowGet);//Sucess
                return Json( new { id= tempId }, JsonRequestBehavior.AllowGet);//Sucess
                     
            }



    // on New Order Template popup Save button click
        var btnSave = document.getElementById('OrderTemplate_Save');
        if (btnSave != null) {
            btnSave.onclick = savenewordertemplate;
        }
        
        function savenewordertemplate() {        
            var newOrderTemplateName = $("#newOrderTemplateName").val();
     
            $.ajax({
                url: Sana.Urls.Home() + 'profile/ordertemplates/savenewordertemplate',
                method: "POST",
                data: { name: newOrderTemplateName }
                ,
                //error: function () {
                //    alert("Ajax call failed");
                //}
            }).done(function (data) {
     
                if (data != null) {
     
                    if (data.id == 0) {                    
                        var error = data.error;
                        $("#template_invalid").append(error);
                        return;
                    }
     
                    var id = data.id;
                    var retunurl = Sana.Urls.Home() + "profile/ordertemplates/details?templateId=" + id;
                    window.location.replace(retunurl);
                }
                
            })
        }

    to open popup javascript 
    var el = document.getElementById('SaveOrderTemplate_test');
        if (el != null) {
            el.onclick = openRegisterTerms;
        }
     
     
        function openRegisterTerms() {
            Sana.Popup.open('#createOrderTemplatePopup');
        }

    popup view 

    _CreateOrderTemplate.cshtml

    @model NewOrderTemplateModel
     
    <div id="createOrderTemplatePopup" style="displaynone;">
        
        <div class="cnt-column">
            <h2>@Sana.SimpleText("OrderTemplate_SavePopupHeader")</h2>
            @*@Html.EditorForModel()*@
            @*<input type="text" id="newOrderTemplateName" name="OrderTemplateName">*@
            @Html.TextBox("newOrderTemplateName", Model.Name)
            <div id="template_invalid"></div>
        </div>
        <div class="ftr-column">
            <a class="btn-cancel btn-close-dialog" title="@Sana.SimpleText("ButtonText_Cancel")">
                <span class="btn-cnt">@Sana.SimpleText("ButtonText_Cancel")</span>
            </a> 
            <a id="OrderTemplate_Save" class="btn btn-small">@Sana.SimpleText("save""save")</a>
     
     
        </div>
     
    </div>

    //--------------------------

    need to try by passinf model .

    for Forehand Project

    https://sanacommerce.visualstudio.com/Sana%20Projects/_workitems/edit/92470/

    https://sanacommerce.visualstudio.com/Sana%20Projects/_workitems/edit/92470/

        ExtendedOrdersController

    [HttpPost]
    [SanaValidateAntiForgeryToken]
            [RequireAbility(AbilityTo.PromoteQuote)]
            public virtual ActionResult PromoteToOrderWithData(string quoteId, string referanceNo = nullstring deliveryDate = nullbool ignoreWarning = false)
            {
                ...

                // Ticket 92470: [Forehand] 3.6. Quote-to-order conversion – Requested delivery date and reference no.
                // Update Reference No and Delivery Date.
                if (!deliveryDate.IsNullOrWhiteSpace())
                {
                    var date = DateTime.Parse(deliveryDate);
                    quote.RequestedDeliveryDate = new Date(date);
                }
                if (!string.IsNullOrEmpty(referanceNo))
                {
                    quote.ReferenceNo = referanceNo;
                }

                ...
            } 

    ExtendedOrderDetailsModel

    public class ExtendedOrderDetailsModel : OrderDetailsModel
        {
            /// Ticket 92470: [Forehand] 3.6. Quote-to-order conversion – Requested delivery date and reference no.
            /// <summary>
            /// Get or set the reference number.
            /// </summary>        
            [AllowHtml]
            //[Required(ErrorMessage = "Name Required")]
            [StringLength(20, ErrorMessageResourceName = SanaTextKeys.MaxLength)]
            [Display(Name = "ReferenceNumber")]
            [ReferenceNoConditionalRequired(ErrorMessageResourceName = SanaTextKeys.RequiredField)]
            public string ReferenceNumber { getset; }

            /// Ticket 92470: [Forehand] 3.6. Quote-to-order conversion – Requested delivery date and reference no.
            /// <summary>
            /// Get or set the delivery date.
            /// </summary>
            [Display(Name = "RequestedDeliveryDate")]
            [GreaterThanToday(ErrorMessageResourceName = SanaTextKeys.InvalidField)]
            public Date? DeliveryDate  { getset; }
        }


    to view add form section to handle validate by it self.
    button set to type Submit

    _PromotePopups.cshtml

    <div id="quotePromotionConfirmationPopup" class="popup-cnt">
            @*<form id="quotePromotionForm" onsubmit="return saveQuoteInfo2()">*@
            <form id="quotePromotionForm"> <------
                <div class="cnt-column">
                    <h2>@Sana.SimpleText("QuotePromotionConfirmationPopup_Title")</h2>
                    <div>@Sana.RichText("QuotePromotionConfirmationPopup_Description", makeImagesResponsive: false)</div>
                </div>
     
                <div>
                    @Html.Partial("_QuoteInfo", model)
                </div>
     
                <div class="ftr-column">
                    @cancelBtn
                    @*@promoteBtn*@               
     
                    @* Ticket 92470: [Forehand] 3.6. Quote-to-order conversion – Requested delivery date and reference no. *@               
                    <input type="submit" id="QuoteInfo_Submit" value="Continue" class="btn btn-small btn-action btn-continue-promote" />
                </div>
            </form> 
        </div>





    add Quantity text box


    _QuickOrder.cshtml.


    Project name : Colruty_935
    _QuickTemplateAdd.cshtml 

    <div class="tbx tbx-quantity" style="display:none">
                    @{
                        string dataBind =
                            @"value: quantity,
                                    attr: {
                                        'data-val-regex': validationMessage(),
                                        'data-min': minimumQuantity(), 'data-val-min': minimumValidationMessage(),
                                        'data-max': maximumQuantity(), 'data-val-max': maximumValidationMessage(),
                                        'data-step': quantityStep(), 'data-val-step': validationMessage()
                                    },
                                    attributeToObservable: {
                                        'data-min-msg-pattern': 'minimumValidationMessagePattern',
                                        'data-max-msg-pattern': 'maximumValidationMessagePattern',
                                        'data-step-msg-pattern': 'validationMessagePattern'
                                    },
                                    numericInputUpdate: selectedUom";
                    }
     
                    <input type="text" class="numeric" name="quantity" maxlength="8" data-val="true"
                           data-val-regex-pattern="@Patterns.Quantity"
                           data-min-msg-pattern="@Sana.SimpleText("ProductDetails_MinimumQuantityValidation").Decode()"
                           data-max-msg-pattern="@Sana.SimpleText("ProductDetails_MaximumQuantityValidation").Decode()"
                           data-step-msg-pattern="@Sana.SimpleText("Validation_QuantityValue").Decode()"
                           data-bind="@dataBind" data-spinner-init="event" />
                    <span class="compact-sign-error field-validation-valid" data-valmsg-for="quantity" data-valmsg-replace="true"></span>
                </div>

    add to the relevant javascript file
    Sana.Spinner.init();

    Error 1

    followig validation will comes when we update content with partial view 2nd time
    then we need reset the validation. 


    //Validattion need to reset after replacing partial view
                            $("form").removeData("validator");
                            $("form").removeData("unobtrusiveValidation");
                            $.validator.unobtrusive.parse("form");


    eg: divercy Project,
    control.quickorder.js
    When a user do a quick search and click add to template button > Partial view data repace > then need to reset the validations
    //When Click Add to Template button 
            $(document).on('click''.btn-add-to-template'function (event) {
                
                var url = $(".btn-add-to-template").attr('data-src');
                var templateId = $('input[name="TemplatePopupForm_TemplateId"]').val();
                url = url + "?templateId=" + templateId;
     
                var data = self._getAddedTemplateLines();
     
                var existingData = self._readExistingQuantities();
     
                Sana.UI.LoadingIndicator.show();            
     
                return $.ajax({
                    url: url,
                    type: 'post',
                    data: JSON.stringify(data),
                    contentType: 'application/json',
                    success: function (data) {
                                            
                        // window.location.reload(true);
                        debugger;
                        if (data != null && data != '') {
                            if (data.templatePartialView != null) {
                                $('.template-replace-area').replaceWith(data.templatePartialView);
                            }
                            if ($('.template-replace-area').length == 0) {
                                $('.template-popup-form').wrap("<div class='template-replace-area'></div>");
                            }
     
                            //When user add new items keep the Previous qty. 
                            self._updateQuantities(existingData);
     
                            $(".btn-add-to-template-area").hide();
                            $(".gvi-template-lines-added > tbody > tr").remove();
     
                            $("#AddLinesToBasket").show();
                            $("#ClearQuantities").show();
                            Sana.UI.LoadingIndicator.hide();
     
                            //Validattion need to reset after replacing partial view
                            $("form").removeData("validator");
                            $("form").removeData("unobtrusiveValidation");
                            $.validator.unobtrusive.parse("form");
     
                            Sana.Spinner.init();
                        }
                    }
                });           
     
            });