diff --git a/00_Assets/Pasted image 20250427152717.png b/00_Assets/Pasted image 20250427152717.png new file mode 100644 index 0000000..0f46cfb Binary files /dev/null and b/00_Assets/Pasted image 20250427152717.png differ 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 ?