├── src ├── store │ ├── actions │ │ ├── userActions.js │ │ └── cartActions.js │ ├── reducers │ │ ├── userReducer.js │ │ └── cartReducer.js │ ├── initialValues │ │ └── cartItems.js │ ├── configureStore.js │ └── rootReducer.js ├── App.css ├── pages │ ├── CartDetail.jsx │ ├── ProductAdd.jsx │ ├── ProductDetail.jsx │ └── ProductList.jsx ├── setupTests.js ├── App.test.js ├── index.css ├── reportWebVitals.js ├── Services │ └── productService.js ├── layouts │ ├── SignedOut.jsx │ ├── Categories.jsx │ ├── SignedIn.jsx │ ├── CartSummary.jsx │ ├── Dashboard.jsx │ └── Navi.jsx ├── App.js ├── index.js ├── utilities │ └── customFormControls │ │ └── KodlamaIoTextInput.jsx ├── dersNotlar.txt └── logo.svg ├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── .gitignore ├── package.json └── README.md /src/store/actions/userActions.js: -------------------------------------------------------------------------------- 1 | // user ile ilgili actionlar burada olacak -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esrasnck/reactForNorthwind/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esrasnck/reactForNorthwind/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esrasnck/reactForNorthwind/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/store/reducers/userReducer.js: -------------------------------------------------------------------------------- 1 | //bunu karşılayacak reducerlar (user actionını) burada olacak -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .ui.main.container{ 6 | margin-top: 6em; 7 | } -------------------------------------------------------------------------------- /src/store/initialValues/cartItems.js: -------------------------------------------------------------------------------- 1 | //export const cartItems=[{quantity:1, product:{productName:"Çubuk kraker"}}] 2 | 3 | // amaç bunu her yerde tetikletmek. 4 | 5 | export const cartItems=[] 6 | -------------------------------------------------------------------------------- /src/pages/CartDetail.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function CartDetail() { 4 | return ( 5 |
6 | Sepet Detayı 7 |
8 | ) 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore } from "redux"; 2 | import { devToolsEnhancer } from "redux-devtools-extension"; 3 | import rootReducer from "./rootReducer"; 4 | 5 | export function configureStore(){ 6 | return createStore(rootReducer,devToolsEnhancer()) 7 | } 8 | 9 | // devToolsEnhancer : -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/Services/productService.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | export default class ProductService{ 4 | 5 | getProducts(){ 6 | return axios.get("http://localhost:8080/api/products/getall") 7 | } 8 | 9 | getProductByName(productName){ 10 | return axios.get("http://localhost:8080/api/products/getByProductName?productName="+ productName ) 11 | } 12 | } 13 | 14 | 15 | 16 | // servis isteklerimi buradan yapacam -------------------------------------------------------------------------------- /src/layouts/SignedOut.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Menu, Button } from "semantic-ui-react"; 3 | 4 | export default function SignedOut({signedIn}) { 5 | return ( 6 |
7 | 8 | 9 | 10 | 11 |
12 | ); 13 | } 14 | 15 | // parametre olarak obje istediğinden iki tane süslü parantez kullanıyoruz. 16 | -------------------------------------------------------------------------------- /src/layouts/Categories.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Menu } from 'semantic-ui-react'; 3 | 4 | export default function Categories() { 5 | return ( 6 |
7 | 8 | 12 | 16 | 20 | 21 |
22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | import Dashboard from './layouts/Dashboard.jsx'; 3 | import 'semantic-ui-css/semantic.min.css'; 4 | import { Container } from 'semantic-ui-react'; 5 | import Navi from "./layouts/Navi"; 6 | 7 | function App() { // app isimli bir component arıyor arkadas 8 | return ( 9 | // className='App' diyerek, app isimli bir css arıyor 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | ); 20 | } 21 | 22 | export default App; 23 | 24 | 25 | // div kısmına jsx deniyor. x=> xml den geliyor. -------------------------------------------------------------------------------- /src/store/rootReducer.js: -------------------------------------------------------------------------------- 1 | // tüm stateleri topladığım yer 2 | 3 | import { combineReducers } from "redux"; 4 | import cartReducer from "./reducers/cartReducer"; 5 | 6 | // tek bir yerde toplayım. uygulamaya onu ekleyim dediğim yer. 7 | // redux'la gelen fonksiyon : combine reducer 8 | 9 | const rootReducer =combineReducers({ 10 | cart : cartReducer, 11 | // user:userReducer => gibi 12 | }) 13 | 14 | export default rootReducer; // default olarak çıkarmak istersem böyle yaparım. 15 | 16 | // bundan sonra yapılacaklar: 17 | 18 | // 1) actionlar yazmak. 19 | // 2) initial value varsa onu yazmak 20 | // 3) reducer'ı yazmak 21 | // buraya eklemek 22 | 23 | // son olarak da mağazayı oluşturcam -------------------------------------------------------------------------------- /src/store/actions/cartActions.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART= "ADD_TO_CART" // magic string => yazım hatasından kurtulmak için bir yerde sabitlemeye çalışıyoruz. 2 | export const REMOVE_FROM_CART= "REMOVE_FROM_CART" 3 | 4 | export function addToCart(product){ 5 | 6 | return{ 7 | 8 | type :ADD_TO_CART, 9 | payload: product 10 | } 11 | } 12 | 13 | export function removeFromCart(product){ 14 | 15 | return{ 16 | 17 | type :REMOVE_FROM_CART, 18 | payload: product 19 | } 20 | } 21 | 22 | 23 | // redux diyor ki bir aksiyon yaptığında bana bir obje gönder. bu objenin içerisinde bu aksiyonun 24 | // ismi olsun (neyi çalıştırcağımı 25 | // bileyim. => type // payload : aksiyonla beraber gönderdiğini, state'i etkileyecek veri. 26 | 27 | 28 | // bu fonksiyon, ADD_TO_CART'ın hangi değerleri etkilediğini bulacak. -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | import { BrowserRouter } from 'react-router-dom'; 7 | import {Provider} from "react-redux"; 8 | import { configureStore } from './store/configureStore'; 9 | 10 | 11 | const store = configureStore() 12 | 13 | // sanal bir virtual dom 14 | 15 | ReactDOM.render( // tüm uygulamayı provider ile sarmalla diyorum (react-redux ile) burada bir store geç diyorum 16 | 17 | 18 | , 19 | document.getElementById('root') 20 | ); 21 | 22 | // If you want to start measuring performance in your app, pass a function 23 | // to log results (for example: reportWebVitals(console.log)) 24 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 25 | reportWebVitals(); 26 | 27 | 28 | // root component app. ilk başlanan component 29 | // component drilling => componentleri yukardan aşağı / aşağıdan yukarı taşımak. -------------------------------------------------------------------------------- /src/layouts/SignedIn.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Dropdown, Menu, Image } from "semantic-ui-react"; 3 | 4 | export default function SignedIn({signedOut}) { 5 | 6 | // props => üst compenentten gelen signedOut={handleSignOut} bisey="1" kısım. ben parametre olarak verdiğim propslardaki 7 | // singOut'u metodunu, onClick ile çalıştıracam. propslar buraya obje olarak geliyor. encapsulation var burada. destruction yaparsın burada. 8 | // objeleri props =>{signIn} şeklinde destruc edebiliyoruz 9 | 10 | return ( 11 |
12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /src/layouts/CartSummary.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { NavLink } from 'react-router-dom'; 3 | import { Dropdown,Label} from "semantic-ui-react"; 4 | import { useSelector } from 'react-redux'; 5 | 6 | export default function CartSummary() { 7 | 8 | const {cartItems} = useSelector(state => state.cart) // state deki cartItems'i çekecez 9 | 10 | return ( 11 |
12 | 13 | 14 | { 15 | cartItems.map((cartItem)=> ( 16 | 17 | 18 | {cartItem.product.productName} 19 | 20 | 21 | 22 | )) 23 | 24 | } 25 | 26 | 27 | 28 | Sepete Git 29 | 30 | 31 |
32 | ) 33 | } 34 | // sepete git e tıkladığımda sepete gitmek istiyorum. react router dom dan gelen bir element ile bunu yapıyoruz. -------------------------------------------------------------------------------- /src/utilities/customFormControls/KodlamaIoTextInput.jsx: -------------------------------------------------------------------------------- 1 | import { useField } from 'formik'; 2 | import React from 'react' 3 | import { FormField,Label } from 'semantic-ui-react'; 4 | 5 | export default function KodlamaIoTextInput({...props}) { 6 | 7 | console.log(props); 8 | // formik te ilgli input elemanınızla ilgili bilgi toplayabilmenizi sağlayan hook var. bunun adı useField 9 | // arkaplanda reflect api kullanıyor. => reflect api bak. 10 | const [field,meta] =useField(props) // props ile gelen field için. onu da name den yakalıyor 11 | 12 | console.log(field) // onchange'i value u vs. veriyor field 13 | console.log(meta) // bir hava var mı? varsa onun değeri bu diyor. touch ise dokunuldu demek. oraya girdim ve çıktım demek 14 | // ürün fiyatı zorunlu kısmı, o touch a dokunulduğu için çıkıyor. meta= hata var mı yok mu o bilgiyi veriyor. 15 | return ( 16 | 17 | 18 | {meta.touched && !!meta.error ? ( 19 | 20 | ):null} 21 | 22 | ) 23 | } 24 | 25 | // !!meta.error metinsel ifadede metin varsa true yoksa false yap demek. -------------------------------------------------------------------------------- /src/dersNotlar.txt: -------------------------------------------------------------------------------- 1 | store: mağaza 2 | 3 | initial values : başlangıç (ör : çılgın çubuk kraker) 4 | 5 | actions : işlem yapan fonksiyon (örnek sepete at/ekleme işlemi) 6 | 7 | reducer : state'in değeri. sepetimizin son değeri. ilk etapta boş. 8 | 9 | ** action=> reducerlara gönderdiğin operasyonlar. reducer gönderilen aksiyon hangi state de var. ben onu tetikleyim diyor. 10 | 11 | Store => actions var. butona tıkladığımızda biz aslında sepete ekleme action'ını çağırmış olacaz. 12 | Store da yine state'ı tutan reducerlarımız var. ben bu reducer' add to cart acitonının göndercem 13 | Add to cart i gönderdiğin anda, bu actionları bellekte tutuyor aslında. bu action'ın hangi reducer da çağırlıdığına bakıyor. 14 | bu reducer'ın içerisine gönderdiğimiz için, addTocart' a göre ne işlemi yapıldğına bakıyor (sepete ekleme) 15 | 16 | biz buraya iki şey gönderiyoruz aslında. 1) aksiyonun tipini, 2.sinde de veri var mı diye bakıyor.(payload kısmında) 17 | 18 | // ** bu yaptığımız şey, bir yerde birşey olduğunda, diğer componente haber vermek için yapılmış bir durum. 19 | 20 | 21 | // cqrs(comment query request pattern) = bir fonksiyon'u parametre olarak gönderiyoruz. comment pattern implementasyonu => araştır ? 22 | 23 | // aksiyonlara abone olmak için kullanılan hook : useDispatch -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "camp-project", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.13.0", 7 | "@testing-library/react": "^11.2.7", 8 | "@testing-library/user-event": "^12.8.3", 9 | "animate.css": "^4.1.1", 10 | "axios": "^0.21.1", 11 | "formik": "^2.2.9", 12 | "react": "^17.0.2", 13 | "react-dom": "^17.0.2", 14 | "react-redux": "^7.2.4", 15 | "react-router-dom": "^5.2.0", 16 | "react-scripts": "4.0.3", 17 | "react-toastify": "^7.0.4", 18 | "redux": "^4.1.0", 19 | "redux-devtools-extension": "^2.13.9", 20 | "semantic-ui-css": "^2.4.1", 21 | "semantic-ui-react": "^2.0.3", 22 | "web-vitals": "^1.1.2", 23 | "yup": "^0.32.9" 24 | }, 25 | "scripts": { 26 | "start": "react-scripts start", 27 | "build": "react-scripts build", 28 | "test": "react-scripts test", 29 | "eject": "react-scripts eject" 30 | }, 31 | "eslintConfig": { 32 | "extends": [ 33 | "react-app", 34 | "react-app/jest" 35 | ] 36 | }, 37 | "browserslist": { 38 | "production": [ 39 | ">0.2%", 40 | "not dead", 41 | "not op_mini all" 42 | ], 43 | "development": [ 44 | "last 1 chrome version", 45 | "last 1 firefox version", 46 | "last 1 safari version" 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/pages/ProductAdd.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Formik, Form,Field,ErrorMessage } from "formik"; 3 | import * as Yup from "yup"; 4 | import { FormField, Button,Label} from "semantic-ui-react"; 5 | import KodlamaIoTextInput from "../utilities/customFormControls/KodlamaIoTextInput"; 6 | 7 | export default function ProductAdd() { 8 | const initialValues = { productName: "", unitPrice: 10 }; 9 | 10 | const schema = Yup.object({ // kuralları da burada yazılı zaten 11 | productName: Yup.string().required("Ürün adı Zorunludur."), 12 | unitPrice: Yup.number().required("Ürün fiyatı zorunludur."), 13 | }); 14 | 15 | return ( 16 |
17 | { 20 | console.log(values) 21 | }}> 22 |
23 | 24 | 25 | {/* 26 | 27 | 28 | 29 | }> 30 | */} 31 | {/* 32 | 33 | 34 | 35 | }> 36 | */} 37 | 38 | 39 |
40 |
41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/pages/ProductDetail.jsx: -------------------------------------------------------------------------------- 1 | import React, {useState , useEffect}from "react"; 2 | import { useParams } from "react-router-dom"; 3 | import { Button, Card, Image } from 'semantic-ui-react' 4 | import ProductService from "../Services/productService"; 5 | 6 | export default function ProductDetail() { 7 | // bu fonksiyon(useParams) parameterleri obje olarak veriyor bana. destruct ediyoruz. 8 | let { name } = useParams(); 9 | 10 | const [product, setproduct] = useState({}) // ilk değeri boş bir obje 11 | 12 | useEffect(() => { 13 | let productService = new ProductService(); 14 | productService.getProductByName(name).then(result=> setproduct(result.data.data)) 15 | 16 | }, []) 17 | 18 | return ( 19 |
20 | 21 | 22 | 23 | 24 | 29 | {product.productName} 30 | {product.category?.categoryName} 31 | 32 | Steve wants to add you to the group best friends 33 | 34 | 35 | 36 |
37 | 40 | 43 |
44 |
45 |
46 |
47 |
48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /src/layouts/Dashboard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ProductList from "../pages/ProductList"; 3 | import Categories from "./Categories"; 4 | import ProductAdd from "../pages/ProductAdd"; 5 | 6 | import { Grid } from 'semantic-ui-react'; 7 | import { Route } from "react-router"; 8 | import ProductDetail from "../pages/ProductDetail"; 9 | import CartDetail from "../pages/CartDetail"; 10 | import { ToastContainer } from "react-toastify"; 11 | import "animate.css/animate.min.css"; 12 | import "react-toastify/dist/ReactToastify.css"; 13 | 14 | 15 | 16 | export default function Dashboard() { 17 | return ( 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | ); 38 | } 39 | 40 | // route işlemini istediğimiz ana componentde yapabiliriz. 41 | // biz roota tıklayınca, productList componenti değişcek. o yüzden bir root'u productlis kısmını silip oraya ekleyeğic 42 | //(Grid.column withd={12} kısmının içi) 43 | 44 | // rout'un çalışabilmesi için,bizim ana birleşinizimi browser rooter ile sarmalamamız gerekli.=> index.js deki app 45 | 46 | // sana ana sayfa dediğimde(path olarak) bana bunu ver demiş oluyoruz. 47 | // exact => tam yol demek. default'u true. -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/store/reducers/cartReducer.js: -------------------------------------------------------------------------------- 1 | import { ADD_TO_CART, REMOVE_FROM_CART } from "../actions/cartActions"; 2 | import { cartItems } from "../initialValues/cartItems"; 3 | 4 | const initialState = { 5 | cartItems: cartItems, 6 | // x:1, 7 | // y:2 // birden çok eleman olabilir burada. o yüzden aşağıda cartItems'ı ayırdım 8 | }; 9 | 10 | // gönderdiğim aksiyona göre sepetin son halini tuttuğumuz yer. 11 | // state=> başlangıç değerim 12 | 13 | export default function cartReducer(state = initialState, { type, payload }) { 14 | switch (type) { 15 | 16 | case ADD_TO_CART: 17 | let product = state.cartItems.find(c=> c.product.id === payload.id) 18 | 19 | if (product) { 20 | product.quantity ++; // bunu yapınca bir bir artar quantity. ama referanslar değişmez. yani sepeti güncellemez. bu yüzden refransı 21 | return{ // güncellemek gerek. o yüzden spread operatörü gerekli 22 | 23 | ...state 24 | // yepyeni bir cart objesini döndürmüş oluyorsun. newliyorsun bir nevi. 25 | } 26 | } else { 27 | 28 | return { // sepette eleman yoksa, yepyeni bir obje oluştur. o zaman mevcut cartItems a yeni bir eleman ekleyip, yeni array yapacam. 29 | 30 | ...state, // cartItems'ı ayırdım. sonra yeni bir array oluşturdum 31 | cartItems:[...state.cartItems,{quantity:1, product:payload}] // sadece bir elamanı değiştirmek istediğim için bu hareketi yapıyorum 32 | // [state'deki cartItems'ı spread et dedim] 33 | // payload'lada yenisi ekledim. 34 | 35 | } 36 | 37 | } 38 | 39 | case REMOVE_FROM_CART: 40 | return{ 41 | ...state, 42 | cartItems:state.cartItems.filter(c=> c.product.id===payload.id) // eşit olanları filtreliyor. filter a yeni bir array oluştur. filtreme göre diyorum. 43 | 44 | } 45 | 46 | default: 47 | return state; // state'in kendisini döndür. 48 | } 49 | } 50 | 51 | // gönderilecek olan type a göre state'i değiştirmek gerekiyor. redux bunu bir şekilde kendi mimarisinde implement ediyor 52 | 53 | // mutebility : sepet elemanlarının değiştiğini redux, (bu hooklarda da geçerli) eğer referansı değiştiyse, 54 | // ben sepete yeni eleman eklendi yada silindi olarak anlarım diyor. sepetin değiştiğini anlarım diyor. o yüzden 55 | // sen benim abonelerimi bilgilendirmen için, ilgi state'in referansını değiştir diyor. 56 | 57 | // bu yüzden benim referansı değiştirmem gerek. o yüzden if blogu is coming 58 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/layouts/Navi.jsx: -------------------------------------------------------------------------------- 1 | import React,{useState} from "react"; 2 | import { useHistory } from "react-router-dom"; 3 | import { Container, Menu } from "semantic-ui-react"; 4 | import CartSummary from "./CartSummary"; 5 | import SignedIn from "./SignedIn"; 6 | import SignedOut from "./SignedOut"; 7 | import { useSelector } from "react-redux"; 8 | 9 | export default function Navi() { 10 | // const diyerek destructor işlemi gerçekleştirecez => initialState öncekinde ürünler olduğu için, state'i boş arraydi. fakat bu durumda 11 | // içerisinde birşeyler olduğundan(state durumu) bunun da default'u ya truedur ya da false dur. 12 | 13 | const [isAuthenticated, setIsAuthenticated] = useState(true) 14 | const history = useHistory() 15 | const {cartItems} = useSelector(state => state.cart) 16 | 17 | function handleSignOut(){ // çıkış yapma işlemini handle edecez. 18 | 19 | setIsAuthenticated(false) // bu fonksiyonu çağıracak olan da alt component 20 | // offline olunca, product sayfasına geri dönmek için, burada useHistory'i kullanıyoruz 21 | 22 | history.push("/") 23 | } 24 | 25 | function handleSignIn() { 26 | setIsAuthenticated(true) 27 | } 28 | 29 | return ( 30 |
31 | 32 | 33 | 34 | 35 | 36 | {cartItems.length>0 && } 37 | { // angularda ngIf ile yapıyordur. burada js kullanacaz. isAuthenticated ve setIsAuthenticated'ı destructe yapacaz. 38 | // useState bize ayrı ayrı iki tane bilgi geçiyor. biz de onu destructe ediyoruz. 39 | // çıkış yapa bastığımda, isAuthenticated'ı değiştirmem gerekiyordu. onu değiştiren fonksiyon, setIsAuthenticated 40 | // sen setIsAuthenticated'ı kullanarak, ona true ya da false değerini verebilirsin. 41 | 42 | isAuthenticated ? : 43 | 44 | // sanki singed'in içinde signedOut diye bir fonksiyon var da, o da aslında handleSignOut fonksiyonunu tetikliyor 45 | // bisey de bunun içindeki değer. bunlara props diyoruz. Bu değerler orada nasıl kullanacaz? => signedIn 'e git 46 | 47 | } 48 | 49 | 50 | 51 | 52 | 53 |
54 | ); 55 | } 56 | 57 | // eğer kişi authentice olduysa signed in i göster, authentice olmamışsa sign-out u göster diyor. 58 | // buna karar veren navi. state'i tutan navi. (Fatiq'in state mevzusu buradan geliyor.) 59 | 60 | // ** reactta bir componente, senin bir şarta göre birşeyler yapman gerekiyorsa, bir datayı tutman gerekiyorsa, 61 | // orada aklına state gelecek. yani o componentin datası. bu işin en basic kısmı. biz bir sonraki aşamada alt componentte data taşıycaz. 62 | 63 | 64 | // hangisini gösterceğine karar veren navi olduğundan senin state bilgisini burada tutman gerek -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /src/pages/ProductList.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Icon, Menu, Button, Table } from "semantic-ui-react"; 3 | import ProductService from "../Services/productService"; 4 | import {Link} from "react-router-dom"; 5 | import { useDispatch } from "react-redux"; 6 | import {addToCart} from "../store/actions/cartActions" 7 | import { toast } from "react-toastify"; 8 | 9 | export default function ProductList() { 10 | 11 | const dispatch = useDispatch() // bu benden çalıştıracağım fonksiyonun ismini istiyor 12 | 13 | const handleAddToCart=(product)=>{ 14 | dispatch(addToCart(product)) 15 | toast.success(`${product.productName} sepete eklendi !`,{ position: toast.POSITION.BOTTOM_RIGHT,}) 16 | 17 | } 18 | 19 | const [products, setProducts] = useState([]); 20 | 21 | // const [state, setstate] = useState(initialState) // intialState başlangıç durumu. datanın başlangıcı boş array 22 | 23 | // sol taraf bir fonksiyon. sağ taraftaki ise bomboş bir array almış 24 | // useState bize bir nesne döndürüyor. onu da destructor edecez. döndürdüğü yerde bir data bir de fonksiyon döndürüyor. 25 | 26 | // benim products diye bir datam var. default değeri boş bir array. setProducts ise bunun hook'u 27 | // lifecycle hook.=> reactın yaşam döngüsüne müdehale etmeye yarıyor. 28 | // lifecycle hookun bir çoğu burada çözülüyor. 29 | useEffect(() => { // component yükelndiğinde yapılmasını istedğin kodu bu bloga yazıyoruz 30 | 31 | let productService = new ProductService() 32 | 33 | productService.getProducts().then(result => setProducts(result.data.data) // axios result da data dışında başka sey de döndürür. o yüzden data nın datası 34 | 35 | 36 | ).catch() // başarılı olursa then. başarısız olursa catch (promise yapısı) 37 | 38 | 39 | 40 | }, []) //=>bunu yapmayınca networke sürekli istekde bulunuyor. 41 | // bir nesnenin her değişikliğe uğradığında sayfanın yeninden render edilmesini istersek, 42 | // burada onu o array içine yazarak (state bilgisini) takibini yapabiliyoruz. aksi takdirde elemanlar değişiğinde yeni istek atıyor. 43 | // ürünler değişiyor. state değiştiği için yeniden istek atıyor vs. hooklarda çalışırken, bunları eklemek önemli. 44 | 45 | 46 | return ( 47 | // hareketli kısım kanımca 48 |
49 | 50 | 51 | 52 | Ürün Adı 53 | Birim Fiyatı 54 | Stok Adedi 55 | Açıklama 56 | Kategori 57 | Sepete Ekle 58 | 59 | 60 | 61 | 62 | { 63 | // js kodları buraya yazılacak. arrayı tekrar edip buraya yazacaz. 64 | // parantez jsx üret ve onu döndür demek 65 | // componentDidMount = ngOnInit() hook kullandığımız için bunu kullanamıuoruz. sayfa yenilendi. bu hooku değiştir 66 | // data değiştiği anda, yenisi render ediliuor. 67 | products.map((product) => ( 68 | 69 | {product.productName} 70 | {product.unitPrice} 71 | {product.unitsInStock} 72 | {product.quantityPerUnit} 73 | {product.category.categoryName} 74 | 75 | 76 | )) 77 | } 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 1 88 | 2 89 | 3 90 | 4 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
99 |
100 | ); 101 | } 102 | 103 | // ürünler bizim için bu sayfadaki state datasıdır. Bunun için hook tekniğini kullancağız. 104 | 105 | 106 | // aksiyonlara abone olmak için kullanılan hook : useDispatch 107 | 108 | // dispatch : fonksiyon çağırmak için kullanılan fonksiyon (reflection gibi) 109 | 110 | 111 | // onclick'e bu fonksiyonu ata diyorum --------------------------------------------------------------------------------