ASP.NET Web API Project Creating
This API allows operations with users and their products, such as adding, deleting, and updating data.
Main functions of the API:
- Retrieving a user and their products:
Allows retrieving information about a user by their ID, along with the list of products they own. - Adding a product to a user:
Allows adding a product to a specific user, expanding their list of items. - Removing a product from a user:
Allows removing a specific product from the user’s list of products. - Changing the price of a product:
Allows modifying the price of a product for a specific user. - Retrieving a list of all users and their products:
Returns information about all users and their products.
The API uses the Kasutaja class to handle users and the Toode class to handle products, providing interaction between them. Additionally, React will be used as the front-end framework to interact with the API, enabling dynamic and responsive user interfaces.
Create a new project in Visual Studio
Choose ASP.NET Core Web API

Write a proper name for the project

Put these options like on the screenshot

Choose http type

Functionality
CONTROLLER – PrimitiividController.cs
After launching you should see something like this (name of the project was changed)

Add a new “API Controller – Empty” to Controllers folder


Add this code into new controller
to recieve straight up results from this functions without swagger’s visualization, before every function is GET query, simply put it in search tab (after code there is every example)
using Microsoft.AspNetCore.Mvc;
namespace veeb.Controllers
{
[Route("[controller]")]
[ApiController]
public class PrimitiividController : ControllerBase
{
private Random rand = new Random();
// GET: primitiivid/hello-world
[HttpGet("hello-world")]
public string HelloWorld()
{
return "Hello world at " + DateTime.Now;
}
// GET: primitiivid/hello-variable/mari
[HttpGet("hello-variable/{nimi}")]
public string HelloVariable(string nimi)
{
return "Hello " + nimi;
}
// GET: primitiivid/add/5/6
[HttpGet("add/{nr1}/{nr2}")]
public int AddNumbers(int nr1, int nr2)
{
return nr1 + nr2;
}
// GET: primitiivid/multiply/5/6
[HttpGet("multiply/{nr1}/{nr2}")]
public int Multiply(int nr1, int nr2)
{
return nr1 * nr2;
}
// GET: primitiivid/do-logs/5
[HttpGet("do-logs/{arv}")]
public void DoLogs(int arv)
{
for (int i = 0; i < arv; i++)
{
Console.WriteLine("See on logi nr " + (i+1));
}
}
// GET: primitiivid/random/5/15
[HttpGet("random/{min}/{max}")]
public int GetRandomNumber(int min, int max)
{
return rand.Next(min, max + 1); // Juhuslik arv, mis jääb min ja max vahemikku
}
// GET: primitiivid/calculate-age/1995/06/15
[HttpGet("calculate-age/{birthYear}/{birthMonth}/{birthDay}")]
public string CalculateAge(int birthYear, int birthMonth, int birthDay)
{
DateTime today = DateTime.Now;
DateTime birthDate = new DateTime(birthYear, birthMonth, birthDay);
int age = today.Year - birthYear;
// Kontrollime, kas sünnipäev on juba olnud sel aastal
if (today.Month < birthMonth || (today.Month == birthMonth && today.Day < birthDay))
{
age--;
}
return $"Oled {age} aastat vana.";
}
}
}
Hello World with date

Hello World with variable

Summ

Multiply

Logs

Random number

Age calculator

CLASS – Toode.cs
Add new folder Models and class Toode.cs


Put this code into the new class
namespace SBD.Models
{
public class Toode
{
public int Id { get; set; }
public string Nimi { get; set; }
public double Price { get; set; }
public bool IsActive { get; set; }
public Toode(int id, string nimi, double price, bool isActive)
{
Id = id;
Nimi = nimi;
Price = price;
IsActive = isActive;
}
}
}
CONTROLLER ToodeController.cs
add new API Controller named ToodeController
Put this code into new controller
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SBD.Models;
namespace SBD.Controllers
{
[Route("[controller]")]
[ApiController]
public class ToodeController : ControllerBase
{
private static Toode _toode = new Toode(1, "Koola", 1.5, true);
// GET: toode
[HttpGet]
public Toode GetToode()
{
return _toode;
}
// GET: toode/suurenda-hinda
[HttpGet("suurenda-hinda")]
public Toode SuurendaHinda()
{
_toode.Price = _toode.Price + 1;
return _toode;
}
// GET: toode/muuda-aktiivsust
[HttpGet("muuda-aktiivsust")]
public Toode MuudaAktiivsust()
{
_toode.IsActive = !_toode.IsActive; // Muudab aktiivsust true <-> false
return _toode;
}
// GET: toode/muuda-nime/KoolaZero
[HttpGet("muuda-nime/{uusNimi}")]
public Toode MuudaNime(string uusNimi)
{
_toode.Nimi = uusNimi; // Määrab uue nime
return _toode;
}
// GET: toode/muuda-hinda/3
[HttpGet("muuda-hinda/{kordaja}")]
public Toode MuudaHinda(double kordaja)
{
_toode.Price = _toode.Price * kordaja; // Korrutab hinna kordajaga läbi
return _toode;
}
}
}
List Selection

Cost Increasing

Setting Active state

Rename

Cost changing

CONTROLLER TootedController.cs
add new API Controller named TootedController
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SBD.Models;
namespace SBD.Controllers
{
[ApiController]
[Route("[controller]")]
public class TootedController : ControllerBase
{
private static List<Toode> _tooted = new List<Toode>{
new Toode(1,"Koola", 1.5, true),
new Toode(2,"Fanta", 1.0, false),
new Toode(3,"Sprite", 1.7, true),
new Toode(4,"Vichy", 2.0, true),
new Toode(5,"Vitamin well", 2.5, true)
};
[HttpGet]
// GET /tooted
public List<Toode> Get()
{
return _tooted;
}
// GET /tooted/kustuta/1
[HttpGet("kustuta/{index}")]
public List<Toode> Delete(int index)
{
_tooted.RemoveAt(index - 1);
return _tooted;
}
// GET /tooted/kustuta2/1
[HttpGet("kustuta2/{index}")]
public string Delete2(int index)
{
_tooted.RemoveAt(index - 1);
return "Kustutatud!";
}
// PUT /tooted/uuenda/6/Pepsi/4/true
// adds new or updates existed
[HttpPut("uuenda/{id}/{nimi}/{hind}/{aktiivne}")]
public List<Toode> Update(int id, string nimi, double hind, bool aktiivne)
{
var existingToode = _tooted.FirstOrDefault(t => t.Id == id);
if (existingToode != null)
{
existingToode.Nimi = nimi;
existingToode.Price = hind;
existingToode.IsActive = aktiivne;
}
else
{
Toode toode = new Toode(id, nimi, hind, aktiivne);
_tooted.Add(toode);
}
return _tooted;
}
// GET /tooted/lisa?id=1&nimi=Koola&hind=1.5&aktiivne=true
[HttpGet("lisa")]
public List<Toode> Add2([FromQuery] int id, [FromQuery] string nimi, [FromQuery] double hind, [FromQuery] bool aktiivne)
{
Toode toode = new Toode(id, nimi, hind, aktiivne);
_tooted.Add(toode);
return _tooted;
}
// GET /tooted/hind-dollaritesse/1.5
[HttpGet("hind-dollaritesse/{kurss}")]
public List<Toode> Dollaritesse(double kurss)
{
for (int i = 0; i < _tooted.Count; i++)
{
_tooted[i].Price = _tooted[i].Price * kurss;
}
return _tooted;
}
// või foreachina:
// GET /tooted/hind-dollaritesse2/1.5
[HttpGet("hind-dollaritesse2/{kurss}")]
public List<Toode> Dollaritesse2(double kurss)
{
foreach (var t in _tooted)
{
t.Price = t.Price * kurss;
}
return _tooted;
}
// GET /tooted/kustuta-koik
[HttpGet("kustuta-koik")]
public List<Toode> DeleteAll()
{
_tooted.Clear();
return _tooted;
}
// GET /tooted/muuda-aktiivsus-valeks
[HttpGet("muuda-aktiivsus-valeks")]
public List<Toode> DeactivateAll()
{
foreach (var t in _tooted)
{
t.IsActive = false;
}
return _tooted;
}
// GET /tooted/1
[HttpGet("{index}")]
public ActionResult<Toode> GetToodeByIndex(int index)
{
if (index < 0 || index >= _tooted.Count)
{
return NotFound("Toodet ei leitud.");
}
return _tooted[index - 1];
}
// GET /tooted/korgeim-hind
[HttpGet("korgeim-hind")]
public ActionResult<Toode> GetMostExpensiveToode()
{
if (_tooted.Count == 0)
{
return NotFound("Tooteid pole saadaval.");
}
var kallimToode = _tooted.OrderByDescending(t => t.Price).FirstOrDefault();
return kallimToode;
}
}
}
Listed items

Delete by id

Delete but you see only message that something was deleted


Adds new or updates product

Different way of add

Changing price in dollars but you must put exchange rate

Different calculational way of exchange rate

Diplays biggest price

Displays product by index

Changes Active state to false for all products

Deletes all

CLASS – Kasutaja.cs
Add new class Kasutaja.cs


Put this code into the new class
namespace SBD.Models
{
public class Kasutaja
{
public int Id { get; set; }
public string Nimi { get; set; }
public int Parool { get; set; }
public string Eesnimi { get; set; }
public string Perenimi { get; set; }
public Kasutaja(int id, string nimi, int parool, string eesnimi, string perenimi)
{
Id = id;
Nimi = nimi;
Parool = parool;
Eesnimi = eesnimi;
Perenimi = perenimi;
}
}
}
add new API Controller named KasutajaController and KasutajadController
CONTROLLER KasutajaController.cs
using Microsoft.AspNetCore.Mvc;
using SBD.Models;
namespace SBD.Controllers
{
[Route("[controller]")]
[ApiController]
public class KasutajaController : ControllerBase
{
private static Kasutaja _kasutaja = new Kasutaja(1, "kasutajanimi", 1234, "Eesnimi", "Perenimi");
// GET: kasutaja
[HttpGet]
public Kasutaja GetKasutaja()
{
return _kasutaja;
}
// GET: kasutaja/muuda-nime/UusNimi
[HttpGet("muuda-nime/{uusNimi}")]
public Kasutaja MuudaNime(string uusNimi)
{
_kasutaja.Nimi = uusNimi;
return _kasutaja;
}
// GET: kasutaja/muuda-parooli/5678
[HttpGet("muuda-parooli/{uusParool}")]
public Kasutaja MuudaParooli(int uusParool)
{
_kasutaja.Parool = uusParool;
return _kasutaja;
}
// GET: kasutaja/muuda-eesnime/Eesnimi
[HttpGet("muuda-eesnime/{uusEesnimi}")]
public Kasutaja MuudaEesnime(string uusEesnimi)
{
_kasutaja.Eesnimi = uusEesnimi;
return _kasutaja;
}
// GET: kasutaja/muuda-perenime/Perenimi
[HttpGet("muuda-perenime/{uusPerenimi}")]
public Kasutaja MuudaPerenime(string uusPerenimi)
{
_kasutaja.Perenimi = uusPerenimi;
return _kasutaja;
}
}
}
CONTROLLER KasutajadController.cs
using Microsoft.AspNetCore.Mvc;
using SBD.Models;
namespace SBD.Controllers
{
[ApiController]
[Route("[controller]")]
public class KasutajadController : ControllerBase
{
private static List<Kasutaja> _kasutajad = new List<Kasutaja>{
new Kasutaja(1, "kasutaja1", 1234, "Eesnimi1", "Perenimi1"),
new Kasutaja(2, "kasutaja2", 5678, "Eesnimi2", "Perenimi2"),
new Kasutaja(3, "kasutaja3", 9101, "Eesnimi3", "Perenimi3")
};
[HttpGet]
// GET /kasutajad
public List<Kasutaja> Get()
{
return _kasutajad;
}
// GET /kasutajad/kustuta/1
[HttpGet("kustuta/{id}")]
public List<Kasutaja> Delete(int id)
{
var kasutaja = _kasutajad.FirstOrDefault(k => k.Id == id);
if (kasutaja != null)
{
_kasutajad.Remove(kasutaja);
}
return _kasutajad;
}
// GET /kasutajad/lisa/4/uusKasutaja/9876/Eesnimi4/Perenimi4
[HttpGet("lisa/{id}/{nimi}/{parool}/{eesnimi}/{perenimi}")]
public List<Kasutaja> Add(int id, string nimi, int parool, string eesnimi, string perenimi)
{
Kasutaja kasutaja = new Kasutaja(id, nimi, parool, eesnimi, perenimi);
_kasutajad.Add(kasutaja);
return _kasutajad;
}
// GET /kasutajad/muuda-parooli/1/5678
[HttpGet("muuda-parooli/{id}/{uusParool}")]
public List<Kasutaja> MuudaParooli(int id, int uusParool)
{
var kasutaja = _kasutajad.FirstOrDefault(k => k.Id == id);
if (kasutaja != null)
{
kasutaja.Parool = uusParool;
}
return _kasutajad;
}
// GET /kasutajad/kustuta-koik
[HttpGet("kustuta-koik")]
public List<Kasutaja> DeleteAll()
{
_kasutajad.Clear();
return _kasutajad;
}
// GET /kasutajad/1
[HttpGet("{id}")]
public ActionResult<Kasutaja> GetKasutajaById(int id)
{
var kasutaja = _kasutajad.FirstOrDefault(k => k.Id == id);
if (kasutaja == null)
{
return NotFound("Kasutajat ei leitud.");
}
return kasutaja;
}
}
}
CONTROLLER KasutajaToodeController.cs
this controller will work with kasutaja and toode classes together
using Microsoft.AspNetCore.Mvc;
using SBD.Models;
using System.Collections.Generic;
using System.Linq;
namespace SBD.Controllers
{
[ApiController]
[Route("[controller]")]
public class KasutajaToodeController : ControllerBase
{
private static List<Kasutaja> _kasutajad = new List<Kasutaja>{
new Kasutaja(1, "kasutaja1", 1234, "Eesnimi1", "Perenimi1"),
new Kasutaja(2, "kasutaja2", 5678, "Eesnimi2", "Perenimi2")
};
private static List<Toode> _tooted = new List<Toode>{
new Toode(1, "Koola", 1.5, true),
new Toode(2, "Fanta", 1.0, false),
new Toode(3, "Sprite", 1.7, true)
};
// list for users
private static Dictionary<int, List<Toode>> _kasutajaTooted = new Dictionary<int, List<Toode>>{
{ 1, new List<Toode>{ _tooted[0], _tooted[1] } }, // kasutaja1 - Koola and Fanta
{ 2, new List<Toode>{ _tooted[2] } } // kasutaja2 - Sprite
};
// GET: kasutaja-toode/{userId}
// Gives users and their list of products
[HttpGet("{userId}")]
public ActionResult<Kasutaja> GetKasutajaWithTooded(int userId)
{
var kasutaja = _kasutajad.FirstOrDefault(k => k.Id == userId);
if (kasutaja == null)
{
return NotFound("Kasutajat ei leitud.");
}
var kasutajaTooted = _kasutajaTooted.ContainsKey(userId) ? _kasutajaTooted[userId] : new List<Toode>();
return Ok(new { kasutaja, tooted = kasutajaTooted });
}
// POST: kasutaja-toode/lisa-toode/{userId}/{toodeId}
// Adds product to the user list
[HttpPost("lisa-toode/{userId}/{toodeId}")]
public ActionResult AddToodeToKasutaja(int userId, int toodeId)
{
var kasutaja = _kasutajad.FirstOrDefault(k => k.Id == userId);
if (kasutaja == null)
{
return NotFound("Kasutajat ei leitud.");
}
var toode = _tooted.FirstOrDefault(t => t.Id == toodeId);
if (toode == null)
{
return NotFound("Toodet ei leitud.");
}
if (!_kasutajaTooted.ContainsKey(userId))
{
_kasutajaTooted[userId] = new List<Toode>();
}
_kasutajaTooted[userId].Add(toode);
return Ok(new { message = "Toode lisatud!", kasutaja, tooded = _kasutajaTooted[userId] });
}
// DELETE: kasutaja-toode/eemalda-toode/{userId}/{toodeId}
// Deletes user's product
[HttpDelete("eemalda-toode/{userId}/{toodeId}")]
public ActionResult RemoveToodeFromKasutaja(int userId, int toodeId)
{
if (!_kasutajaTooted.ContainsKey(userId) || !_kasutajaTooted[userId].Any(t => t.Id == toodeId))
{
return NotFound("Toodet või kasutajat ei leitud.");
}
var toode = _kasutajaTooted[userId].FirstOrDefault(t => t.Id == toodeId);
_kasutajaTooted[userId].Remove(toode);
return Ok(new { message = "Toode eemaldatud!", tooded = _kasutajaTooted[userId] });
}
// PUT: kasutaja-toode/muuda-hinda/{userId}/{toodeId}/{uusHind}
// Changes the price of a product for the user
[HttpPut("muuda-hinda/{userId}/{toodeId}/{uusHind}")]
public ActionResult UpdateToodePriceForKasutaja(int userId, int toodeId, double uusHind)
{
if (!_kasutajaTooted.ContainsKey(userId) || !_kasutajaTooted[userId].Any(t => t.Id == toodeId))
{
return NotFound("Toodet või kasutajat ei leitud.");
}
var toode = _kasutajaTooted[userId].FirstOrDefault(t => t.Id == toodeId);
toode.Price = uusHind;
return Ok(new { message = "Toote hind muudetud!", tooded = _kasutajaTooted[userId] });
}
// GET: kasutaja-toode/koik-tooted
// Returns a list of all users and their products
[HttpGet("koik-tooted")]
public ActionResult GetAllKasutajadWithTooded()
{
var result = _kasutajad.Select(k => new
{
kasutaja = k,
tooted = _kasutajaTooted.ContainsKey(k.Id) ? _kasutajaTooted[k.Id] : new List<Toode>()
}).ToList();
return Ok(result);
}
}
}

Frontend with React.js
Before we start, put this code in your Program.cs
app.UseCors(options => options
.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader()
);

React we are using to set a frontend for our website, back end is in visual studio in SBD porject, and they will synchronize between each other


cd /your_directory
npx create-react-app frontend
Open “frontend” file in PHPStorm or VS Code (download extensions for convinience)
should be looking like this

then write in console:
cd frontend
npm start

in App.js put this code, if something not working try checking and changing links and https/http and change your localhost:xxxx to that you have in swagger

import { useEffect, useRef, useState } from 'react';
import './App.css';
function App() {
const [tooted, setTooted] = useState([]);
const idRef = useRef();
const nameRef = useRef();
const priceRef = useRef();
const isActiveRef = useRef();
const [isUsd, setUsd] = useState(false);
useEffect(() => {
fetch("http://localhost:5249/Tooted")
.then(res => res.json())
.then(json => setTooted(json));
}, []);
function kustuta(index) {
fetch("http://localhost:5249/Tooted/kustuta/" + index)
.then(res => res.json())
.then(json => setTooted(json));
}
function lisa() {
fetch(`http://localhost:5249/Tooted/lisa/${Number(idRef.current.value)}/${nameRef.current.value}/${Number(priceRef.current.value)}/${isActiveRef.current.checked}`)
.then(res => res.json())
.then(json => setTooted(json));
}
function dollariteks() {
const kurss = 1.1;
setUsd(true);
fetch("http://localhost:5249/Tooted/hind-dollaritesse/" + kurss)
.then(res => res.json())
.then(json => setTooted(json));
}
function eurodeks() {
const kurss = 0.9091;
setUsd(false);
fetch("http://localhost:5249/Tooted/hind-dollaritesse/" + kurss)
.then(res => res.json())
.then(json => setTooted(json));
}
return (
<div className="App">
<label>ID</label> <br />
<input ref={idRef} type="number" /> <br />
<label>name</label> <br />
<input ref={nameRef} type="text" /> <br />
<label>price</label> <br />
<input ref={priceRef} type="number" /> <br />
<label>isActive</label> <br />
<input ref={isActiveRef} type="checkbox" /> <br />
<button onClick={() => lisa()}>Lisa</button>
{tooted.map((toode, index) =>
<div>
<div>{toode.id}</div>
<div>{toode.nimi}</div>
<div>{toode.price.toFixed(2)}</div>
<button onClick={() => kustuta(index)}>x</button>
</div>)}
{isUsd === false && <button onClick={() => dollariteks()}>Muuda dollariteks</button>}
{isUsd === true && <button onClick={() => eurodeks()}>Muuda eurodeks</button>}
</div>
);
}
export default App;
Now we have a visualization of our back-end work

Now we will test our queries through postman
Some examples:



PUT method

Now we will look at three controllers that provide different functionality.
Create these controllers same as before
ParcelMachineController.cs
This Controller will give information about Omniva Parcels
Back-End
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace SBD.Controllers
{
[Route("[controller]")]
[ApiController]
public class ParcelMachineController : ControllerBase
{
private readonly HttpClient _httpClient;
public ParcelMachineController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet("omniva")]
public async Task<IActionResult> GetParcelMachinesOmniva()
{
var response = await _httpClient.GetAsync("https://www.omniva.ee/locations.json");
var responseBody = await response.Content.ReadAsStringAsync();
return Content(responseBody, "application/json");
}
}
}
Front-End
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [pakiautomaadid, setPakiautomaadid] = useState([]);
useEffect(() => {
fetch("http://localhost:5249/ParcelMachine/omniva")
.then(res => res.json())
.then(json => setPakiautomaadid(json));
}, []);
return (
<div className="App">
<select>
{pakiautomaadid.map(automaat =>
<option>
{automaat.NAME}
</option>)}
</select>
</div>
);
}
export default App;
Result

NordpoolController.cs
Back-End
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
namespace SBD.Controllers
{
[Route("[controller]")]
[ApiController]
public class NordpoolController : ControllerBase
{
private readonly HttpClient _httpClient;
public NordpoolController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet("{country}/{start}/{end}")]
public async Task<IActionResult> GetNordPoolPrices(
string country,
string start,
string end)
{
var response = await _httpClient.GetAsync(
$"https://dashboard.elering.ee/api/nps/price?start={start}&end={end}");
var responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
var jsonDoc = JsonDocument.Parse(responseBody);
var dataProperty = jsonDoc.RootElement.GetProperty("data");
string prices;
switch (country)
{
case "ee":
prices = dataProperty.GetProperty("ee").ToString();
Console.WriteLine(responseBody);
return Content(prices, "application/json");
case "lv":
prices = dataProperty.GetProperty("lv").ToString();
return Content(prices, "application/json");
case "lt":
prices = dataProperty.GetProperty("lt").ToString();
return Content(prices, "application/json");
case "fi":
prices = dataProperty.GetProperty("fi").ToString();
return Content(prices, "application/json");
default:
return BadRequest("Invalid country code.");
}
}
}
}
Front-End
import { useRef } from 'react';
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [prices, setPrices] = useState([]);
const [chosenCountry, setChosenCountry] = useState("ee");
const [start, setStart] = useState("");
const [end, setEnd] = useState("");
const startRef = useRef();
const endRef = useRef();
useEffect(() => {
if (start !== "" && end !== "") {
fetch("http://localhost:5249/nordpool/" + chosenCountry + "/" + start + "/" + end)
.then(res => res.json())
.then(json => {
setPrices(json);
});
}
}, [chosenCountry, start, end]);
function updateStart() {
const startIso = new Date(startRef.current.value).toISOString();
setStart(startIso);
}
function updateEnd() {
const endIso = new Date(endRef.current.value).toISOString();
setEnd(endIso);
}
return (
<div>
<button onClick={() => setChosenCountry("fi")}>Soome</button>
<button onClick={() => setChosenCountry("ee")}>Eesti</button>
<button onClick={() => setChosenCountry("lv")}>Läti</button>
<button onClick={() => setChosenCountry("lt")}>Leedu</button>
<input ref={startRef} onChange={updateStart} type="datetime-local" />
<input ref={endRef} onChange={updateEnd} type="datetime-local" />
{prices.length > 0 &&
<table style={{marginLeft: "100px"}}>
<thead>
<th style={{border: "1px solid #ddd", padding: "12px", backgroundColor: "#04AA6D"}}>Ajatempel</th>
<th style={{border: "1px solid #ddd", padding: "12px", backgroundColor: "#04AA6D"}}>Hind</th>
</thead>
<tbody>
<td style={{position: "absolute", left: "30px"}}>{chosenCountry}</td>
{prices.map(data =>
<tr key={data.timestamp}>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{new Date(data.timestamp * 1000).toISOString()}</td>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{data.price}</td>
</tr>)}
</tbody>
</table>}
</div>
);
}
export default App;
Result

PaymentController.cs
Back-End
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text;
namespace SBD.Controllers
{
[Route("[controller]")]
[ApiController]
public class PaymentController : ControllerBase
{
private readonly HttpClient _httpClient;
public PaymentController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet("{sum}")]
public async Task<IActionResult> MakePayment(string sum)
{
var paymentData = new
{
api_username = "e36eb40f5ec87fa2",
account_name = "EUR3D1",
amount = sum,
order_reference = Math.Ceiling(new Random().NextDouble() * 999999),
nonce = $"a9b7f7e7as{DateTime.Now}{new Random().NextDouble() * 999999}",
timestamp = DateTime.Now,
customer_url = "https://maksmine.web.app/makse"
};
var json = JsonSerializer.Serialize(paymentData);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "ZTM2ZWI0MGY1ZWM4N2ZhMjo3YjkxYTNiOWUxYjc0NTI0YzJlOWZjMjgyZjhhYzhjZA==");
var response = await client.PostAsync("https://igw-demo.every-pay.com/api/v4/payments/oneoff", content);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var jsonDoc = JsonDocument.Parse(responseContent);
var paymentLink = jsonDoc.RootElement.GetProperty("payment_link");
return Ok(paymentLink);
}
else
{
return BadRequest("Payment failed.");
}
}
}
}
Front-End
import React, { useState } from 'react';
import './App.css';
function App() {
const [amount, setAmount] = useState('');
const [paymentLink, setPaymentLink] = useState(null);
const [error, setError] = useState(null);
const makePayment = async () => {
setError(null);
try {
const response = await fetch(`http://localhost:5249/Payment/${amount}`);
if (!response.ok) {
throw new Error(`Error Fetching: ${response.status}`);
}
const data = await response.json();
setPaymentLink(data);
} catch (err) {
setError(err.message);
}
};
const handleSubmit = (event) => {
event.preventDefault();
makePayment();
};
return (
<div className="App">
<h1>Make a Payment</h1>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="amount">Enter Amount: </label>
<input
id="amount"
type="number"
value={amount}
onChange={e => setAmount(e.target.value)}
required
min="0.01"
step="0.01"
placeholder="Enter amount in EUR"
/>
</div>
<button type="submit">Pay</button>
</form>
{error && <p style={{ color: 'red' }}>Error: {error}</p>}
{paymentLink ? (
<div>
<h2>Payment Link:</h2>
<a href={paymentLink} target="_blank" rel="noopener noreferrer">
Complete Payment
</a>
</div>
) : (
<p>No payment link available</p>
)}
</div>
);
}
export default App;
Result



Now we will do login and register into account with database
So that only registered users can make purchases
Back-End
Create new Folder “Data”

In Data folder create class ApplicationDbContext and put the code there
ApplicationDbContext.cs
using Microsoft.EntityFrameworkCore;
using SBD.Models;
namespace SBD.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Kasutaja> Kasutajad { get; set; }
public DbSet<Toode> Tooted { get; set; }
}
}
now go to Tools -> NuGet Package Manager -> Package Manager Console and do 2 commands
Add-Migration InitialCreate
Update-Database
Now you will have database with your tables that are in Models folder

Front-End
Create AuthPage.js and put the code there for login and register function
AuthPage.js
import React, { useState } from 'react';
import axios from 'axios';
const AuthPage = ({ onLoginSuccess }) => {
const [isRegistering, setIsRegistering] = useState(false);
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [error, setError] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
const userData = {
nimi: username,
parool: password,
eesnimi: firstName,
perenimi: lastName
};
const url = isRegistering
? 'http://localhost:5249/api/Kasutajad/register'
: 'http://localhost:5249/api/Kasutajad/login';
axios.post(url, userData)
.then(response => {
console.log("Registration or login successful:", response.data);
sessionStorage.setItem('userId', response.data.userId);
onLoginSuccess(response.data.userId);
})
.catch(error => {
if (error.response) {
console.error("Server error:", error.response.data);
setError(error.response.data.message || "Ошибка аутентификации!");
} else {
console.error("Network or server error:", error.message);
setError("Network or server error. Please try again.");
}
});
};
return (
<div className="auth-page">
<h1>{isRegistering ? 'Register' : 'Login'}</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Username"
value={username}
onChange={e => setUsername(e.target.value)}
required
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={e => setPassword(e.target.value)}
required
/>
{isRegistering && (
<>
<input
type="text"
placeholder="First Name"
value={firstName}
onChange={e => setFirstName(e.target.value)}
required
/>
<input
type="text"
placeholder="Last Name"
value={lastName}
onChange={e => setLastName(e.target.value)}
required
/>
</>
)}
<button type="submit">{isRegistering ? 'Register' : 'Login'}</button>
<button type="button" onClick={() => setIsRegistering(!isRegistering)}>
{isRegistering ? 'Already have an account? Login' : 'No account? Register'}
</button>
</form>
{error && <p className="error-message">{error}</p>}
</div>
);
};
export default AuthPage;
Modify App.js file
App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css';
import AuthPage from './AuthPage';
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState([]);
const [paymentLink, setPaymentLink] = useState(null);
const [showPayment, setShowPayment] = useState(true);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [userId, setUserId] = useState(null);
useEffect(() => {
const storedUserId = sessionStorage.getItem('userId');
if (storedUserId) {
setIsAuthenticated(true);
setUserId(storedUserId);
}
}, []);
useEffect(() => {
if (isAuthenticated) {
axios.get('http://localhost:5249/tooted')
.then(response => {
setProducts(response.data);
})
.catch(error => {
console.error("There was an error fetching products!", error);
});
}
}, [isAuthenticated]);
const addToCart = (product) => {
const existingProductIndex = cart.findIndex(item => item.id === product.id);
if (existingProductIndex !== -1) {
const updatedCart = cart.map((item, index) =>
index === existingProductIndex ? { ...item, quantity: item.quantity + 1 } : item
);
setCart(updatedCart);
} else {
setCart([...cart, { ...product, quantity: 1 }]);
}
};
const removeFromCart = (index) => {
const newCart = [...cart];
newCart.splice(index, 1);
setCart(newCart);
};
const getTotalPrice = () => {
return cart.reduce((sum, product) => sum + product.price * product.quantity, 0).toFixed(2);
};
const handlePayment = async () => {
if (cart.length === 0) {
alert("Cart is empty. Please add products to proceed with payment.");
return;
}
try {
const totalAmount = getTotalPrice();
const response = await axios.get(`http://localhost:5249/payment/${totalAmount}`);
if (response.status === 200) {
const paymentLink = response.data;
setPaymentLink(paymentLink);
setCart([]);
} else {
alert("Payment initiation failed.");
}
} catch (error) {
console.error("There was an error during payment initiation!", error);
alert("Payment initiation failed.");
}
};
const handleLogout = () => {
setIsAuthenticated(false);
sessionStorage.removeItem('userId');
};
const handleLoginSuccess = (id) => {
setIsAuthenticated(true);
setUserId(id);
sessionStorage.setItem('userId', id);
};
if (!isAuthenticated) {
return <AuthPage onLoginSuccess={handleLoginSuccess} />;
}
return (
<div className="app-container">
<h1>Product List</h1>
<div className="product-list">
{products.map(product => (
<div key={product.id} className="product-item">
<h2>{product.nimi}</h2>
<p>Price: {product.price} EUR</p>
<button onClick={() => addToCart(product)}>Add to Cart</button>
</div>
))}
</div>
<h1>Cart</h1>
<div className="cart">
{cart.length === 0 && <p>Cart is empty</p>}
{cart.map((item, index) => (
<div key={index} className="cart-item">
<h2>{item.nimi}</h2>
<p>Price: {item.price} EUR</p>
<p>Quantity: {item.quantity}</p>
<p>Total: {(item.price * item.quantity).toFixed(2)} EUR</p>
<button onClick={() => removeFromCart(index)}>Remove</button>
</div>
))}
</div>
<h2>Total: {getTotalPrice()} EUR</h2>
<button onClick={handlePayment} className="checkout-btn">Checkout</button>
{paymentLink && showPayment && (
<div className="payment-link-container">
<h2>Proceed to payment:</h2>
<a href={paymentLink} target="_blank" rel="noopener noreferrer" onClick={() => setShowPayment(false)}>
Pay Now
</a>
</div>
)}
<button onClick={handleLogout} className="logout-btn">Logout</button>
</div>
);
};
export default App;
and put css in App.css
App.css
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.app-container {
padding: 20px;
font-family: Arial, sans-serif;
}
h1 {
font-size: 24px;
color: #333;
}
.product-list, .cart {
display: flex;
flex-wrap: wrap;
margin: 10px 0;
}
.product-item, .cart-item {
border: 1px solid #ccc;
padding: 10px;
margin: 5px;
width: 200px;
text-align: center;
}
.product-item button, .cart-item button {
margin-top: 10px;
padding: 5px 10px;
background-color: #28a745;
color: white;
border: none;
cursor: pointer;
}
.product-item button:hover, .cart-item button:hover {
background-color: #218838;
}
.checkout-btn {
padding: 10px 20px;
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
}
.checkout-btn:hover {
background-color: #0056b3;
}
.payment-link-container {
margin-top: 20px;
}
.payment-link-container a {
color: #007bff;
text-decoration: none;
font-weight: bold;
}
.payment-link-container a:hover {
text-decoration: underline;
}
.register-link {
color: blue;
text-decoration: underline;
cursor: pointer;
}
.register-link:hover {
color: darkblue;
}
Now you have working login and register with option to purchase your products
Login

Register

Page where you can manage your order

When you click Checkout, payment link there will appear

Payment
