در این سؤال قرار است که یک زمانسنج ساده با React طراحی کنید.
به این صورت که از لحظه load شدن زمان شروع به افزایش کند
و با فشردن دکمهی `Reset Timer` این زمان مجدداً صفر شود.
![زمانسنج ساده](https://quera.ir/qbox/view/QqVwtjGJ4N/simple-timer.gif)
# پروژه اولیه
پروژه اولیه را از
[اینجا](https://quera.ir/qbox/download/UDq0uUHK3s/simple-timer.zip)
دانلود کنید.
ساختار فایلهای این پروژه به صورت زیر است.
```
simple-timer
├── public
│ ├── favicon.png
│ └── index.html
├── src
│ ├── Timer.css
│ ├── Timer.js
│ └── index.js
├── package.json
└── pnpm-lock.yaml
```
# راهاندازی پروژه
**برای اجرای پروژه، باید `NodeJS` و `npm` (یا `pnpm`) را از قبل نصب کرده باشید.**
- در پوشهی `simple-timer` ، دستور `npm install` را برای نصب نیازمندیها اجرا کنید.
- **نکته:** برای نصب سریعتر از `pnpm install` استفاده کنید.
- در همین پوشه، دستور `npm start` را برای راهاندازی پروژه اجرا کنید.
- با مراجعه به `http://localhost:3000/` میتوانید نتیجه را ببینید.
# جزئیات
شما باید مؤلفهی `Timer` را به صورت زیر تکمیل کنید:
- مؤلفه پس از `load` شدن، ابتدا عدد صفر را نمایش دهد و شروع به شمردن کند (هر یک ثانیه).
- پس از هربار فشردن دکمهی `Reset Timer` زمان مجدداً از صفر آغاز شود.
- توجه کنید که پس از آغاز مجدد زمانسنج، شمارش از ثانیهی صفر تا یک باید دقیقاً ۱ ثانیه طول بکشد.
- هنگام حذف مؤلفه (Unmount) باید زمانبندی ایجاد شده را پاک کنید (`clearInterval`).
# نکات
- زمان باید در عنصر با کلاس `timer` نمایش داده شود (نام کلاس در داوری تاثیر دارد).
- در این سؤال کد شما **نباید** به ساعت سیستم وابسته باشد (مثلاً نباید از `Date` استفاده کنید).
عدد زمانسنج نباید با تغییر ساعت به هم بریزد.
- پس از پیادهسازی، فایل `Timer.js` را ارسال کنید.
زمانسنج ساده
احتمالاً نام ویژگی جدید React یعنی hook را شنیدهاید. با این ویژگی میتوان از state و
امکانات دیگر React در مؤلفههای مبتنی بر تابع استفاده کرد.
![React Hooks](https://quera.ir/qbox/view/ewA5GJ7j59/react-hooks.jpg)
جملهای از مستندات React:
> In the longer term, we expect Hooks to be the primary way people write React components.
در این سؤال از شما میخواهیم دو قلاب سفارشی! (custom hook) ساده را پیادهسازی کنید.
# پروژه اولیه
پروژه اولیه را از
[اینجا](https://quera.ir/qbox/download/hqfITbk0HL/simple-hooks.zip)
دانلود کنید.
ساختار فایلهای این پروژه به صورت زیر است.
```
simple-hooks
├── public
│ ├── favicon.png
│ └── index.html
├── src
│ ├── components.js
│ ├── hooks.js
│ ├── index.css
│ └── index.js
├── README.md
├── package.json
└── pnpm-lock.yaml
```
# راهاندازی پروژه
**برای اجرای پروژه، باید `NodeJS` و `npm` (یا `pnpm`) را از قبل نصب کرده باشید.**
- در پوشهی `simple-hooks` ، دستور `npm install` را برای نصب نیازمندیها اجرا کنید.
- **نکته:** برای نصب سریعتر از `pnpm install` استفاده کنید.
- در همین پوشه، دستور `npm start` را برای راهاندازی پروژه اجرا کنید.
- با مراجعه به `http://localhost:3000/` میتوانید نتیجه را ببینید.
- توجه کنید که در این سؤال اجرای پروژهی اولیه با خطا مواجه میشود
و پس از پیادهسازی قسمتهای مربوطه میتوانید نتیجهی نهایی را مشاهده کنید.
# جزئیات
موارد زیر را در فایل `hooks.js` پیادهسازی کنید.
## ۱. شمارندهی حلقوی
useCounter(start, finish) => [c, count]
این قلاب مقدار شروع و پایان شمارنده را به عنوان ورودی میگیرد و یک آرایه شامل مقدار شمارنده و تابعی برای شمردن برمیگرداند. تابع `count` باید مقدار شمارنده را یک واحد اضافه کند. در صورتی که مقدار شمارنده برابر با `finish` باشد با شمارش بعدی مقدار به `start` تغییر میکند.
مثالی از نحوهی استفاده که در پروژهی اولیه نیز آمده است:
```js
function CounterDemo() {
const [c, count] = useCounter(100, 105);
return <div>
<p>{c}</p>
<button onClick={count}>Count</button>
</div>;
}
```
## ۲. پشته
useStack() => {stack, push, pop}
این قلاب یک پشته را پیادهسازی میکند و در خروجی یک شیء شامل مقادیر پشته (آرایهی `stack`)، تابع `push` برای افزودن عنصر به پشته و تابع `pop` برای حذف آخرین عنصر را برمیگرداند.
مثالی از نحوهی استفاده که در پروژهی اولیه نیز آمده است:
```js
const words = ['Apple', 'Banana', 'Cherry', 'Grape'];
export function StackDemo() {
const {stack, push, pop} = useStack();
return <div>
{words.map((word, index) => <button key={index} onClick={() => push(word)}>{word}</button>)}
<button onClick={pop}>» Pop</button>
<ul>
{stack.map((item, index) => <li key={index}>{item}</li>)}
</ul>
</div>;
}
```
نحوهی عملکرد مثالهای بالا را در شکل زیر میبینید.
![React Hooks](https://quera.ir/qbox/view/klXvjpZyoL/react-hooks-demo.gif)
# نکات
- هر کدام از این دو hook را که پیادهسازی کنید، نمرهی آن را خواهید گرفت.
- پس از پیادهسازی، فایل `hooks.js` را ارسال کنید.
قلابهای ساده
حسنی در دوران تنبلیاش، همهی فیلمهای برتر سینمای جهان را مشاهده کرد
و علاقهی او به سینما از همانجا آغاز شد.
![حسنی در ده شلمرود](https://quera.ir/qbox/view/LqoUHAj3py/hasani.jpg)
بعد از سالها، او به تازگی یک توسعهدهندهی Front-end شده است
و به او پیشنهاد شده که سایت سینما شلمرود را پیادهسازی کند.
اون نیز به دلیل علاقهی زیادی که به سینما دارد این پروژه را به سرعت قبول کرد.
این پروژه یک وبسایت ساده برای نمایش اطلاعات فیلمهای در حال اکران است.
در صفحهی اصلی، لیست فیلمها به صورت تعدادی کارت به نمایش در میآید.
![سینما ۱](https://quera.ir/qbox/view/39ewMd8VVO/cinema1.png)
و با کلیک روی نام هر فیلم به صفحهی جزئیات آن فیلم هدایت میشویم.
![سینما ۲](https://quera.ir/qbox/view/bFIYdV8mPD/cinema2.png)
از آنجایی که حسنی کار با React را یاد گرفته، پروژه را با این کتابخانه آغاز میکند
اما در میانهی کار متوجه میشود که این کتابخانه به تنهایی کافی نیست
و باید راهی برای مدیریت مسیر (`Route`) های مختلف پیدا کند.
پیشنهاد ما به او استفاده از`react-router-dom`
است اما حسنی هیچ دانشی از این کتابخانه ندارد، او را در این مسیر کمک کنید.
# پروژه اولیه
پروژه اولیه را از [اینجا](https://quera.ir/qbox/download/pQ5v4cOWE7/cinema.zip) دانلود کنید.
<details>
<summary>
ساختار فایلهای پروژهی اولیه
</summary>
```
cinema
├── public
│ ├── favicon.png
│ └── index.html
├── src
│ ├── components
│ │ ├── App.js
│ │ ├── MovieCard.js
│ │ ├── MovieDetail.js
│ │ ├── MovieList.js
│ │ ├── Movies.js
│ │ └── NotFound.js
│ ├── server
│ │ ├── static
│ │ │ └── images
│ │ │ ├── se7en-banner.jpg
│ │ │ ├── se7en.jpg
│ │ │ ├── the-prestige-banner.jpg
│ │ │ ├── the-prestige.jpg
│ │ │ ├── v-for-vendetta-banner.jpg
│ │ │ └── v-for-vendetta.jpg
│ │ ├── movies-detail.json
│ │ ├── movies.json
│ │ └── server.js
│ ├── index.js
│ └── style.css
├── package.json
└── pnpm-lock.yaml
```
</details>
# راهاندازی پروژه
**برای اجرای پروژه، باید `NodeJS` و `npm` (یا `pnpm`) را از قبل نصب کرده باشید.**
- در پوشهی `cinema` ، دستور `npm install` را برای نصب نیازمندیها اجرا کنید.
- **نکته:** برای نصب سریعتر از `pnpm install` استفاده کنید.
- در همین پوشه، دستور `npm run server` را برای راهاندازی سرور اجرا کنید.
- در یک ترمینال دیگر، دستور `npm start` را برای راهاندازی کلاینت اجرا کنید.
- با مراجعه به `http://localhost:3000/` میتوانید نتیجه را ببینید.
# جزئیات
هدف این سؤال، سنجش مهارت شما در استفاده از کتابخانهی `react-router-dom` است.
کارهایی که باید انجام دهید در ادامه آمده است.
- تنظیم مسیر (`Route`) های صحیح در مؤلفهی `App`
به طوری که با دسترسی به هر مسیر مؤلفهی مشخصشده نمایش داده شود.
- مسیر اصلی `/`: مؤلفهی `Movies`
- مسیر `/movies/{movie_id}`: مؤلفهی `MovieDetail`
- تمام مسیرهای دیگر: مؤلفهی `NotFound`
- عنوان هر فیلم در مؤلفهی `MovieCard` باید لینک به صفحهی جزئیات همان فیلم باشد.
- باید در مؤلفهی `MovieDetail` یکی از متدهای `lifecycle` مناسب را `override` کنید
به طوری که بلافاصله پس از `load` شدن مؤلفه اطلاعات مربوط به فیلم را از سرور دریافت
و `state` مولفه را بروز کنید.
**دریافت اطلاعات جزئی یک فیلم از سرور:**
- **URL:** `localhost:9000/movies/{movie_id}`
- **Method:** `GET`
# نکات
- شما تنها مجاز به تغییر در فایلهای `App.js`، `MovieCard.js` و `MovieDetail.js` هستید.
- پس از اعمال تغییرات، پروژه را _Zip_ کرده و ارسال کنید.
دقت کنید که پوشهی `node_modules` در فایل ارسالی نباشد.
سینما
**مهارتهای لازم:**
+ آشنایی با `ReactJS`
+ آشنایی با `Redux`
+ کدخوانی
--------------------------------------------------
سینا سعیدی و سعید سینایی برای یادگرفتن redux از نمونههای سایت آن استفاده میکنند. در یکی از این نمونهها سبد خرید سادهای توضیح داده شده است. آنها میخواهد امکانات جدید به سبد خرید اضافه کند که شبیه سایت اسنپ فود شود!
ظاهر کلی برنامه بدین صورت است:
![ظاهر برنامه](https://quera.ir/qbox/view/tmwboiXM0U/overview.png)
# پروژه اولیه
پروژه اولیه را از
[اینجا](https://quera.ir/qbox/download/zvF4TNz479/like-snappfood.zip)
دانلود کنید.
ساختار فایلهای این پروژه به صورت زیر است.
<details>
<summary>
ساختار فایلهای پروژهی اولیه
</summary>
```
like-snappfood
├── public
│ ├── static
│ │ ├── css
│ │ │ └── style.css
│ │ └── images
│ │ ├── delete-icn.svg
│ │ ├── item-1.jpg
│ │ ├── item-2.jpg
│ │ ├── item-3.jpg
│ │ ├── item-4.jpg
│ │ ├── item-5.jpg
│ │ ├── minus.svg
│ │ ├── plus.svg
│ │ └── twitter-heart.png
│ └── index.html
├── src
│ ├── actions
│ │ └── index.js
│ ├── api
│ │ ├── products.json
│ │ └── shop.js
│ ├── components
│ │ ├── Cart.js
│ │ ├── Product.js
│ │ ├── ProductCard.js
│ │ ├── ProductItem.js
│ │ └── ProductsList.js
│ ├── constants
│ │ └── ActionTypes.js
│ ├── containers
│ │ ├── App.js
│ │ ├── CartContainer.js
│ │ └── ProductsContainer.js
│ ├── reducers
│ │ ├── cart.js
│ │ ├── index.js
│ │ └── products.js
│ └── index.js
├── README.md
├── package.json
└── pnpm-lock.yaml
```
</details>
# راهاندازی پروژه
**برای اجرای پروژه، باید `NodeJS` و `npm` را از قبل نصب کرده باشید.**
- ابتدا پروژهی اولیه را دانلود و از حالت فشرده خارج کنید.
- در پوشهی `like-snappfood` ، دستور `npm install` را برای نصب نیازمندیها اجرا کنید.
- در همین پوشه، دستور `npm start` را برای راهاندازی پروژه اجرا کنید.
- پس از انجام موفق این مراحل، با مراجعه به آدرس `http://localhost:3000/` میتوانید نتیجه را ببینید.
# جزئیات
طراحی state برنامه بدین صورت است:
``` js
{
cart: {
addedIds: Array(productIds),
money: Int,
quantityById: Object(productId: quantity)
},
products{
byId: Object(productId: product),
visibleIds: Array(productIds)
}
}
```
- `cart.addedIds`: آرایهای از `id` محصولات که خریداری شدهاند.
- `cart.money`: موجودی شخص برای خرید محصول
- `cart.quantityById`: به ازای هر محصول تعداد خریداری شده را مشخص میکند.
- `products.byId`: به ازای هر `id` تعریف محصول را مشخص میکند.
در این پروژه دو قسمت کلی وجود دارد وجود دارد:
- `ProductsContainer`: قسمتی که کاربر میتواند از آن یک محصول را به سبد خرید خود اضافه کند و به ازای هر محصول یک کارت در آن وجود دارد.
- `CartContainer`: سبد خرید و محصولات موجود در سبد را مشخص میکند. همچنین دارای قسمتی برای نهایی کردن پرداخت میباشد.
داخل فایل `actions/index.js` اطلاعات مربوط به action های شما قرار خواهند گرفت.
در این پروژه پنج نوع action (عملیات) وجود دارد:
- `ADD_TO_CART`: با گرفتن `id` یک محصول تنها در صورتی که از این محصول موجودی داشته باشیم و مقدار پول ما برای سبد خرید با محصول جدید مناسب باشد آن را به سبد محصول اضافه میکند.
این action در صورت کلیک بر روی `Add to cart` و یا دکمه `+` (سبد خرید) فراخوانی خواهد شد. باید یکی از تعداد موجودی محصول کاسته و به تعداد خریداری اضافه شود.
- `TOGGLE_LIKE`: محصولی که در سبد خرید قرار دارد امکان ثبت به عنوان مورد علاقه را دارد. محصولی که ابتدا مورد علاقه شده باشد و از سبد خرید خارج شود پس از اضافه شدن مجدد بایستی مورد علاقه بماند.
این action با کلیک بر روی علامت `♥` در سبد محصول فعال میشود و درنهایت باید پس از مورد علاقه شدن کلاس `is-active` به `like-btn` اضافه شود.
- `REMOVE_FROM_CART`: با گرفتن `id` یک محصول آن را از سبد محصول حذف میکند..
این action با کلیک بر روی دکمه `-` (در سبد خرید) بایستی اجرا شود و یکی از تعداد خریداری (درصورت وجود) کسر شود و به موجودی اضافه شود.
- `REMOVE_ALL_FROM_CART`: تمام محصولات خریداری شده از یک `id` را حذف میکند.
در صورت کلیک بر روی دکمه `×` تمام محصولات از یک `id` حذف شود و به موجودی اضافه شود.
- `CHECKOUT_REQUEST`: سبد خرید خالی شود و قیمت از موجودی کاسته شود.
# نکات
- شما تنها مجاز به اعمال تغییر در فایلهای `components/*`، `containers/CartContainer.js`، `reducers/cart.js` ،`reducers/product.js` و `actions/index.js` هستید.
- پس از اعمال تغییرات، پروژه را _zip_ کرده و ارسال کنید.
دقت کنید که پوشهی `node_modules` در فایل ارسالی نباشد.
شبهاسنپفود
سالها پیش حسنی که دست از تنبلی برداشته بود تصمیم گرفت در کار مزرعه به پدرش کمک کند.
![حسنی در ده شلمرود](https://quera.ir/qbox/view/IlMp75xnOM/shalamrood.jpg)
اکنون که حسنی به توسعهی Front-end علاقهمند شده،
تصمیم گرفته به یاد گذشته و مزرعهی پدری یک بازی با React طراحی کند.
او در میانهی کار به شلمرود رفته و پروژهی نیمهکاره را به شما سپرده تا آن را کامل کنید.
![بازی شلمرود - ۱](https://quera.ir/qbox/view/yf2LNMYCJ2/shalamrood-1.png)
در این بازی، مزرعه به شکل یک جدول از نهرهاست و هدف رساندن آب به همهی نهرهای مزرعه است.
یکی از نهرها منبع آب است. با کلیک روی هر نهر، آن نهر ۹۰ درجه در جهت ساعتگرد میچرخد.
بازی تعدادی مرحله دارد و با حل یک مرحله، (در صورتی که در آخرین مرحله نباشیم)
دکمهی رفتن به مرحلهی بعد فعال میشود.
برای حل یک مرحله باید نهرها در وضعیتی قرار بگیرند که:
1. آب به همهی نهرها برسد.
2. آب هدر نرود. به عبارت دیگر همهی نهرها به هم متصل شوند.
مثلاً در شکل زیر هنوز بازی حل نشده است و برای حل آن باید ۳ بار روی نهر وسط کلیک کنیم.
![بازی شلمرود - ۲](https://quera.ir/qbox/view/LsjbLnQiRl/shalamrood-2.png)
مثالی از بازی را در شکل زیر میبینید. در این مثال بازی تنها ۲ مرحله دارد.
![بازی شلمرود - ۳](https://quera.ir/qbox/view/PdUo4neEmL/shalamrood.gif)
# پروژه اولیه
پروژه اولیه را از [اینجا](https://quera.ir/qbox/download/OKweubYP8V/shalamrood.zip) دانلود کنید.
<details>
<summary>
ساختار فایلهای پروژهی اولیه
</summary>
```
shalamrood
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── components
│ │ ├── board
│ │ │ ├── Board.css
│ │ │ ├── Board.js
│ │ │ ├── Cell.css
│ │ │ └── Cell.js
│ │ ├── menu
│ │ │ ├── Menu.css
│ │ │ └── Menu.js
│ │ ├── App.css
│ │ └── App.js
│ ├── font
│ │ ├── shalamfont.woff2
│ │ └── style.css
│ ├── tests-sample
│ │ ├── __snapshots__
│ │ │ └── shalamrood.test.js.snap
│ │ └── shalamrood.test.js
│ ├── constants.js
│ ├── index.css
│ ├── index.js
│ └── levels.js
├── README.md
├── package.json
└── pnpm-lock.yaml
```
</details>
# راهاندازی پروژه
**برای اجرای پروژه، باید `NodeJS` و `npm` (یا `pnpm`) را از قبل نصب کرده باشید.**
- در پوشهی `shalamrood` ، دستور `npm install` را برای نصب نیازمندیها اجرا کنید.
- **نکته:** برای نصب سریعتر از `pnpm install` استفاده کنید.
- در همین پوشه، دستور `npm start` را برای راهاندازی پروژه اجرا کنید.
- با مراجعه به `http://localhost:3000/` میتوانید نتیجه را ببینید.
- برای اجرای تستهای نمونه `npm test` را اجرا کنید.
# جزئیات
حسنی برای پروژه تعدادی مؤلفه تعریف کرده که در جدول زیر مشاهده میکنید.
او با خواندن مقالهی
[Lifting State Up](https://reactjs.org/docs/lifting-state-up.html)
تصمیم گرفته حالت بازی را در بالاترین مؤلفه یعنی `App` قرار دهد.
| مؤلفه | توضیحات |
|:-----------:|---------------------------------------------------------------------------|
| **`App`** | مؤلفهی اصلی بازی است و حالت بازی در آن قرار دارد. |
| **`Menu`** | مؤلفهی بدون حالت برای نمایش عدد مرحله و دکمههای «مرحله بعد» و «شروع مجدد» |
| **`Board`** | مؤلفهی بدون حالت برای نمایش نهرها |
| **`Cell`** | مؤلفهی بدون حالت برای نمایش یک نهر |
نهرها انواع زیر را دارند:
![انواع نهر در شلمرود](https://quera.ir/qbox/view/pRL9V1lUqZ/cell-types.png)
حالت بازی (حالت مؤلفهی `App`) به صورت زیر است.
```js
{
rows: 3,
cols: 3,
source: 8,
level: 0,
cells: [
{
type: "L",
rotate: 3,
active: false
},
{
type: "T",
rotate: 2,
active: true
},
...
]
}
```
همانطور که مشخص است، تعداد سطرها و ستونها، شمارهی نهر منبع آب (`source`)،
شمارهی مرحلهای که در آن قرار داریم و وضعیت نهرها در حالت قرار میگیرد.
- شمارهی مرحله در `state` از صفر شروع میشود اما هنگام نمایش از یک شروع میشود.
- وضعیت نهرها به صورت سطر به سطر از چپ به راست در آرایهی `cells` قرار میگیرد.
- مقدار `rotate` برای هر نهر عددی بین ۰ تا ۳ است و
نشان میدهد نسبت به وضعیت اصلی نهر که در شکل بالا میبینید چند بار چرخیده است.
- مقدار `active` برای هر نهر نشان میدهد که آب به آن نهر رسیده یا خیر.
بنابراین مقدار `active` برای منبع آب باید همواره `true` باشد.
مواردی که باید پیادهسازی کنید:
## ۱. نمایش اولیه
در نمایش اولیهی مرحلهی اول بازی، باید منبع آب و همهی نهرهایی که آب به آنها میرسد فعال باشند (`active: true`).
دکمهی رفتن به مرحلهی بعد باید غیرفعال باشد
(با [صفت `disabled`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-disabled)).
## ۲. عملکرد صحیح کلیک روی نهرها
با کلیک روی هر نهر، باید حالت به نحوی مناسب تغییر کند تا آن نهر ۹۰ درجه بچرخد
و آب نیز بر اساس وضعیت جدید نهرها به آنها برسد.
## ۳. عملکرد صحیح دکمهها
- در هر مرحلهای که هستیم، کلیک بر روی دکمهی شروع مجدد باید آن مرحله را از ابتدا شروع کند.
- دکمهی مرحلهی بعد باید در صورتی که مرحلهی فعلی حل شده و مرحلهی بعدی نیز وجود دارد فعال باشد
و در غیر این صورت غیرفعال باشد.
- در صورت حل شدن مرحله، دکمهی مرحلهی بعد باید بازی را به مرحلهی بعد ببرد
(عدد مرحله و نهرها باید بهروز شود).
# نکات
- میتوانید در صورت نیاز دادههای دیگری نیز در حالت مؤلفه ذخیره کنید.
اما مجاز به تغییر ساختار دادههای فعلی نیستید.
- شما تنها مجاز به اعمال تغییر در فایلهای `App.js`، `Menu.js`، `Board.js` و `Cell.js` هستید.
- پس از اعمال تغییرات، پروژه را _Zip_ کرده و ارسال کنید.
دقت کنید که پوشهی `node_modules` در فایل ارسالی نباشد.