From 104d41f211bff0f5786e14aa8f51a11233f307ab Mon Sep 17 00:00:00 2001 From: Mehrdad Shirvani Date: Sun, 27 Apr 2025 17:47:07 +0330 Subject: [PATCH] Write Session06 --- 00_Assets/Pasted image 20250427152717.png | Bin 0 -> 11076 bytes 01_IntroductionSessions/Session06/06_Notes.md | 1 + .../Session02/Session 02 Document.md | 4 - .../Session04/Session04.md | 4 +- .../Session05/Session05.md | 727 +++++++++++++++++- .../Session06/Session06.md | 5 + 6 files changed, 721 insertions(+), 20 deletions(-) create mode 100644 00_Assets/Pasted image 20250427152717.png create mode 100644 02_ProjectOrientedSessions/Session06/Session06.md diff --git a/00_Assets/Pasted image 20250427152717.png b/00_Assets/Pasted image 20250427152717.png new file mode 100644 index 0000000000000000000000000000000000000000..0f46cfb6a32e378e803251d5a7e2b8d0cb9e2028 GIT binary patch literal 11076 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 CUd@*P literal 0 HcmV?d00001 diff --git a/01_IntroductionSessions/Session06/06_Notes.md b/01_IntroductionSessions/Session06/06_Notes.md index 1537191..650184b 100644 --- a/01_IntroductionSessions/Session06/06_Notes.md +++ b/01_IntroductionSessions/Session06/06_Notes.md @@ -1,3 +1,4 @@ + # Part 3: SOLID Principle https://www.geeksforgeeks.org/solid-principle-in-programming-understand-with-real-life-examples/ diff --git a/02_ProjectOrientedSessions/Session02/Session 02 Document.md b/02_ProjectOrientedSessions/Session02/Session 02 Document.md index 7616f07..ae06d51 100644 --- a/02_ProjectOrientedSessions/Session02/Session 02 Document.md +++ b/02_ProjectOrientedSessions/Session02/Session 02 Document.md @@ -430,10 +430,6 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); -// Register repositories and Unit of Work -builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); -builder.Services.AddScoped(); - var app = builder.Build(); app.Run(); ``` diff --git a/02_ProjectOrientedSessions/Session04/Session04.md b/02_ProjectOrientedSessions/Session04/Session04.md index 18d44b7..20b0910 100644 --- a/02_ProjectOrientedSessions/Session04/Session04.md +++ b/02_ProjectOrientedSessions/Session04/Session04.md @@ -356,7 +356,7 @@ You are provided with a SQL script, that adds some sample data into the followin # Merge -- [ ]  Create the feature/transportation-search branch based on develop +- [ ] Create a PR and merge the current branch with develop # Additional Info @@ -504,7 +504,7 @@ public class CustomerController : ControllerBase { ## List-like stuff in `C#` Absolutely, let’s go over the main “list-like” data types in C#. They all serve similar purposes—holding multiple items—but differ in functionality, performance, and use cases. Here’s a detailed breakdown: -🔷 1. IEnumerable +🔷 1. `IEnumerable` - Namespace: System.Collections.Generic diff --git a/02_ProjectOrientedSessions/Session05/Session05.md b/02_ProjectOrientedSessions/Session05/Session05.md index c035314..8f64e5b 100644 --- a/02_ProjectOrientedSessions/Session05/Session05.md +++ b/02_ProjectOrientedSessions/Session05/Session05.md @@ -1,27 +1,726 @@ # Preparation +- [ ] Watch https://www.youtube.com/watch?v=SqcY0GlETPk&ab_channel=ProgrammingwithMosh -# Creating a project (Vite) +# CORS (Backend Repository) +- [ ] open `program.cs` and add the following lines -# CORS +```c# +builder.Services.AddCors(options => +{ + options.AddPolicy("Frontend", policy => + { + policy.WithOrigins("http://localhost:5173") + .AllowAnyHeader() + .AllowAnyMethod(); + }); +}); -# Folder Structure +... + +app.UseCors("Frontend"); +``` + + +# **Important Note Before Starting** + +## From now on, this session will be focused on the **frontend repository** + +## If you have already created a the frontend project, with the deprecated command(create-react-app), you need to first delete all that, commit the changes, and then create the project using the next instruction + +# Branching +- [ ] Create the develop branch +- [ ] Create the feature/project-setup branch based on develop + +# Creating a project (using Vite) + +``` +npm create vite@latest alibabaclone-frontend --template react-ts +``` + +# React Folder Structure +- [ ] Create the folders as shown in the picture below +![[Pasted image 20250427154917.png]] +- [ ] move `App.tsx` and `App.css` to 'shared/layout/' +- [ ] adjust the dependencies in these files and `index.html` # Installing packages -uuid -react-router-dom -axios -mobx -redux? -# Models for City / TransportationSearchResult +- [ ] run this command to install these packages: `uuid`, `react-router-dom`, and `axios` +```bash +npm install uuid react-router-dom axios +``` +- [ ] run this command to install redux +```bash +npm install @reduxjs/toolkit react-redux +``` + +# CSS TAILWIND +## **Important Note About CSS** +There are few options and ways to create components, and handle `css` classes. You can can pick any one of them. + +- [ ] install the css/component library of your choice +### For tailwind, use the link below (skip the first step) +Tailwind +https://ui.shadcn.com/docs/installation/vite + +# Merge +- [ ] Create a PR and merge the current branch with develop +# Branching +- [ ] Create the feature/transportation-search branch based on develop +# Creating Models +- [ ] Create models for the DTOs that are used to convey data between backend and frontend +📂 Suggested Folder: shared/models/[relatedFolder] + +Create a `[dtoName].ts` in the related folder, and define the model +## Example: +```ts +export interface TransportationSearchRequest{ +    vehicleTypeId ?: number; +    fromCityId ?: number; +    toCityId ?: number; +    startDate ?: Date | null; +    endDate ?: Date | null; +} +``` + +# Handling API Calls + +- [ ] Create `agent.ts` to handle API calls using axios + +📂 Suggested Folder: shared/api/ + +- [ ] Adjust the `baseURL` to address your web API port + +```ts +import axios, { AxiosResponse } from 'axios'; + +import { TransportationSearchRequest } from '../models/transportation/transportationSearchRequest'; +import { TransportationSearchResult } from '../models/transportation/transportationSearchResult'; + +import { City } from '../models/location/city'; + +axios.defaults.baseURL = 'https://localhost:[REPLACE THIS WITH YOUR BACKEND WEB API PORT]/api'; + +const responseBody = (response: AxiosResponse) => response.data; + +const request = { +    get: (url: string) => axios.get(url).then(responseBody), +    post: (url: string, body: {}) => axios.post(url, body).then(responseBody), +    put: (url: string, body: {}) => axios.put(url, body).then(responseBody), +    delete: (url: string) => axios.delete(url).then(responseBody) +} + +const TransportationSearch = { +    search: (data: TransportationSearchRequest) => request.post('/transportation/search', data), +} + +const Cities = { +    list: () => request.get('/city'), +} + + +const agent = { +    TransportationSearch, +    Cities +} + +export default agent; +``` + +# Creating `CityDropdown` Component +📂 Suggested Folder: shared/api/ +- [ ] Create components for the parts of the UI you need + +```ts +import agent from "@/shared/api/agent"; +import { City } from "@/shared/models/location/city"; +import { useEffect, useState } from "react"; + +const CityDropdown = () => { +  const [cities, setCities] = useState([]); +  const [selectedCity, setSelectedCity] = useState(); + +  useEffect(() => { +    agent.Cities.list() +      .then(setCities) +      .catch((err) => console.error("error loading cities", err)); +  }, []); + +  return ( +    +  ); +}; + +export default CityDropdown; +``` +## **See the analysis of `CityDropdown` component code in the additional info** +# Creating `transportationCard` Component +```ts +import { TransportationSearchResult } from "@/shared/models/transportation/transportationSearchResult"; +import React from "react"; + +interface Props { +  transportation: TransportationSearchResult; +} + +const TransportationCard: React.FC = ({ transportation }) => { +  return ( +   
+      {/* Price and Select Button */} +     
+       
+          {transportation.price} Toman +       
+        +     
+      {/* Trip Info */} +     
+       
+          {transportation.companyTitle} +       
+       
+         
{transportation.fromCityTitle}
+          +         
{transportation.toCityTitle}
+       
+ +       
+          {new Date(transportation.startDateTime).toLocaleDateString("en", { +            hour: "2-digit", +            minute: "2-digit", +          })} +       
+     
+ +      {/* Company Logo or Placeholder */} +     
+        company + +     
+   
+  ); +}; + +export default TransportationCard; +``` + +# Creating `transportationSearchForm` Component + +See the code from: + + +# Additional Notes: +## What is vite +## What is CORS? +### CORS (Cross-Origin Resource Sharing) + +**What it is:** CORS is a browser security feature that blocks requests to a different domain unless explicitly allowed by the server. +### 🔐 What is CORS **really** for? + +CORS is **not** about protecting the backend server. +It’s about **protecting users** from **malicious websites** using their browser as a weapon. + +--- + +### 🧠 Imagine this attack: + +You’re logged into your **bank** in one browser tab (`bank.com`). + +Now, you visit a shady website in another tab (`evil.com`). That site has JavaScript that tries to send this: + +```js +fetch('https://bank.com/api/transfer?amount=5000&to=hacker', { + credentials: 'include' // it sends your bank cookies! +}); +``` + +➡️ If the browser allowed this freely, the request would go through **using your login session**, and you’d lose money. + +--- + +### 💥 Enter CORS + +So the browser says: + +> “Hold on. This JavaScript is from `evil.com`, and it’s trying to talk to `bank.com`. I won’t let that happen **unless `bank.com` says it’s okay**.” + +That’s why the **backend server** must respond with something like: + +```http +Access-Control-Allow-Origin: https://mytrusteddomain.com +``` + +Only then will the browser say, “Okay, go ahead.” + +--- + +### So the purpose of CORS is: + +✅ To **restrict browsers** from sending or accepting responses from **cross-origin** sources +❌ Not to protect the backend +❌ Not to restrict Postman, curl, servers, or mobile apps + +--- + +### 🔄 In Dev Work (like your React + API case): + +- You’re running React at `http://localhost:5173` +- You’re running ASP.NET Core API at `https://localhost:7001` +- The browser sees this as two **different origins** → blocks the request unless CORS is enabled on the API. + +--- + +### 🧪 Why Postman works: +- Postman isn’t a browser +- Postman doesn’t care about same-origin policy +- Postman just sends requests like your backend would + +--- + +### ✅ Conclusion: + +- **CORS is a browser feature to protect users** +- **It restricts frontend JavaScript from calling other domains unless explicitly allowed** +- **You must configure your server to say “Yes, I allow your frontend to talk to me”** + + +## Feature-based Folder Structure +## Explanation of the `agent.ts` + +## React.FC + +### In your code: + +```tsx +const TransportationCard: React.FC = ({ transportation }) => { ... } +``` + +You're using `React.FC`. +✅ `FC` stands for **Function Component**. + +--- + +### So what is `React.FC` exactly? + +- `React.FC` (or `React.FunctionComponent`) is a **TypeScript type** that you can use to type your functional React components. + +- It **tells TypeScript** that: + + - This component is a function + + - It **receives props** (in your case, `Props`) + + - It **returns JSX** (it returns something React can render) + + +--- + +### Why use it? + +Here’s what you get when you use `React.FC`: + +1. ✅ **Prop typing** — You get auto-complete and error checking for props. + +2. ✅ **Children** are automatically included. (More on this below.) + +3. ✅ **Cleaner code** because TypeScript understands the shape of the component. + + +--- + +### Without `React.FC` + +You could just write: + +```tsx +const TransportationCard = ({ transportation }: Props) => { ... } +``` + +and it would work! +But you lose some "extra typing safety" like automatic `children` typing. + +--- + +### Small Detail: `children` + +When you use `React.FC`, **TypeScript automatically** allows your component to accept `children` too — even if you didn’t define it in your `Props`. + +For example: + +```tsx + +

Hello

// This would be valid automatically +
+``` + +Because `children` is **always** part of a `React.FC`. + +👉 If you **don't** use `React.FC`, and you want to accept `children`, you have to **manually** add it to your props. + +--- + +### Some developers today... + +**Some people** (even in big companies) prefer **NOT** to use `React.FC` anymore because: + +- It **forces children** even when you don’t want children. + +- It's **a little bit redundant** — you can already just type props without it. + + +> So in modern codebases, **both styles are OK** — it’s just a preference. + +--- + +### Quick Summary: + +|Using `React.FC`|Not using `React.FC`| +|:--|:--| +|Good for simple, typed functional components|Good if you want full manual control over props| +|Auto-includes `children` prop|You must manually add `children` if needed| +|Easy and quick|More customizable| + +--- + +--- + +Would you like me to also show a real quick **example side-by-side** (with and without `React.FC`) so you can see the difference even more clearly? 🚀 +(It's super fast but very helpful!) + +## `CityDropdown` Component: + +### 1. **State Variables** + +```tsx +const [cities, setCities] = useState([]); +const [selectedCity, setSelectedCity] = useState(); +``` + +- `cities`: holds the list of cities retrieved from the backend (starts empty `[]`). + +- `selectedCity`: holds the currently selected city’s ID (`number`) or `undefined` if nothing is selected yet. + + +--- + +### 2. **Fetching Cities on Mount** + +```tsx +useEffect(() => { + agent.Cities.list() + .then(setCities) + .catch((err) => console.error("error loading cities", err)); +}, []); +``` + +- When the component **mounts** (`[]` dependency array = run once), it calls `agent.Cities.list()`. +- `agent.Cities.list()` presumably returns a promise that resolves to an array of `City` objects. + +- On success → `setCities` updates the `cities` state. + +- On failure → logs an error to the console. + + +--- + +### 3. **Rendering the Dropdown** + +```tsx + +``` + +- Renders a `` dropdown fills up! + +--- + +#### 3. ✏️ Handle input changes + +```tsx +const handleChange = (e: React.ChangeEvent) => { ... } +``` + +Whenever a user types/selects: + +- You detect **which field** (`name`) and **what value** (`value`) they changed + +- Update the `form` state accordingly: + - `fromCityId` and `toCityId` are converted to numbers (`parseInt`) + - `startDate` and `endDate` allow null + - Other fields (if any) are copied directly + +--- + +#### 4. 🔍 Handle Search button + +```tsx +const handleSearch = () => { ... } +``` + +When the user clicks **Search**: + +- Set `loading` to `true` +- Call the backend API `agent.TransportationSearch.search(form)` +- When the result comes back: + - Save it into `searchResults` +- If error: log it +- Finally, set `loading` to `false` again + +--- + +#### 5. 🖥️ Return (render) JSX +You build a UI: + +- **Vehicle Types** (Bus, Train, Airplane) selectable with a click → sets `vehicleTypeId` +- **From City** and **To City** dropdowns +- **Start and End Date** inputs +- **Search Button** to trigger the search +- **Result area** that shows: + - If loading: "Loading..." + - If no results: "No results found" + - If results: List of `TransportationCard` components for each found item. + + +--- + -# axios and API calls -# Store? -# Components -# Pages -# Routing diff --git a/02_ProjectOrientedSessions/Session06/Session06.md b/02_ProjectOrientedSessions/Session06/Session06.md new file mode 100644 index 0000000..35df492 --- /dev/null +++ b/02_ProjectOrientedSessions/Session06/Session06.md @@ -0,0 +1,5 @@ +https://github.com/3lf/design-patterns-for-humans + +# Store? +# Pages? +# Routing ?