زمان‌سنج ساده


در این سؤال قرار است که یک زمان‌سنج ساده با React طراحی کنید. به این صورت که از لحظه load شدن زمان شروع به افزایش کند و با فشردن دکمه‌ی Reset Timer این زمان مجدداً صفر شود.

زمان‌سنج ساده

پروژه اولیه🔗

پروژه اولیه را از اینجا دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

simple-timer
├── public
│   ├── favicon.png
│   └── index.html
├── src
│   ├── Timer.css
│   ├── Timer.js
│   └── index.js
├── package.json
└── pnpm-lock.yaml
Plain text

راه‌اندازی پروژه🔗

برای اجرای پروژه، باید 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

جمله‌ای از مستندات React:

In the longer term, we expect Hooks to be the primary way people write React components.

در این سؤال از شما می‌خواهیم دو قلاب سفارشی! (custom hook) ساده را پیاده‌سازی کنید.

پروژه اولیه🔗

پروژه اولیه را از اینجا دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

simple-hooks
├── public
│   ├── favicon.png
│   └── index.html
├── src
│   ├── components.js
│   ├── hooks.js
│   ├── index.css
│   └── index.js
├── README.md
├── package.json
└── pnpm-lock.yaml
Plain text

راه‌اندازی پروژه🔗

برای اجرای پروژه، باید NodeJS و npm (یا pnpm) را از قبل نصب کرده باشید.

  • در پوشه‌ی simple-hooks ، دستور npm install را برای نصب نیازمندی‌ها اجرا کنید.
    • نکته: برای نصب سریع‌تر از pnpm install استفاده کنید.
  • در همین پوشه، دستور npm start را برای راه‌اندازی پروژه اجرا کنید.
  • با مراجعه به http://localhost:3000/ می‌توانید نتیجه را ببینید.
  • توجه کنید که در این سؤال اجرای پروژه‌ی اولیه با خطا مواجه می‌شود و پس از پیاده‌سازی قسمت‌های مربوطه می‌توانید نتیجه‌ی نهایی را مشاهده کنید.

جزئیات🔗

موارد زیر را در فایل hooks.js پیاده‌سازی کنید.

۱. شمارنده‌ی حلقوی🔗

useCounter(start, finish) => [c, count]
Plain text

این قلاب مقدار شروع و پایان شمارنده را به عنوان ورودی می‌گیرد و یک آرایه شامل مقدار شمارنده و تابعی برای شمردن برمی‌گرداند. تابع count باید مقدار شمارنده را یک واحد اضافه کند. در صورتی که مقدار شمارنده برابر با finish باشد با شمارش بعدی مقدار به start تغییر می‌کند.

مثالی از نحوه‌ی استفاده که در پروژه‌ی اولیه نیز آمده است:

function CounterDemo() {
    const [c, count] = useCounter(100, 105);

    return <div>
        <p>{c}</p>
        <button onClick={count}>Count</button>
    </div>;
}
JavaScript

۲. پشته🔗

useStack() => {stack, push, pop}
Plain text

این قلاب یک پشته را پیاده‌سازی می‌کند و در خروجی یک شیء شامل مقادیر پشته (آرایه‌ی stack)، تابع push برای افزودن عنصر به پشته و تابع pop برای حذف آخرین عنصر را برمی‌گرداند.

مثالی از نحوه‌ی استفاده که در پروژه‌ی اولیه نیز آمده است:

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>;
}
JavaScript

نحوه‌ی عملکرد مثال‌های بالا را در شکل زیر می‌بینید.

React Hooks

نکات🔗

  • هر کدام از این دو hook را که پیاده‌سازی کنید، نمره‌ی آن را خواهید گرفت.
  • پس از پیاده‌سازی، فایل hooks.js را ارسال کنید.

سینما


حسنی در دوران تنبلی‌اش، همه‌ی فیلم‌های برتر سینمای جهان را مشاهده کرد و علاقه‌ی او به سینما از همانجا آغاز شد.

حسنی در ده شلمرود

بعد از سال‌ها، او به تازگی یک توسعه‌دهنده‌ی Front-end شده است و به او پیشنهاد شده که سایت سینما شلمرود را پیاده‌سازی کند. اون نیز به دلیل علاقه‌ی زیادی که به سینما دارد این پروژه را به سرعت قبول کرد.

این پروژه یک وب‌سایت ساده برای نمایش اطلاعات فیلم‌های در حال اکران است. در صفحه‌ی اصلی، لیست فیلم‌ها به صورت تعدادی کارت به نمایش در می‌آید.

سینما ۱

و با کلیک روی نام هر فیلم به صفحه‌ی جزئیات آن فیلم هدایت می‌شویم.

سینما ۲

از آنجایی که حسنی کار با React را یاد گرفته، پروژه را با این کتابخانه آغاز می‌کند اما در میانه‌ی کار متوجه می‌شود که این کتابخانه به تنهایی کافی نیست و باید راهی برای مدیریت مسیر (Route) های مختلف پیدا کند. پیشنهاد ما به او استفاده ازreact-router-dom است اما حسنی هیچ دانشی از این کتابخانه ندارد،‌ او را در این مسیر کمک کنید.

پروژه اولیه🔗

پروژه اولیه را از اینجا دانلود کنید.

ساختار فایل‌های پروژه‌ی اولیه
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
Plain text

راه‌اندازی پروژه🔗

برای اجرای پروژه، باید 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 از نمونه‌های سایت آن استفاده می‌کنند. در یکی از این نمونه‌ها سبد خرید ساده‌ای توضیح داده شده است. آنها می‌‌خواهد امکانات جدید به سبد خرید اضافه کند که شبیه سایت اسنپ فود شود! ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

پروژه اولیه🔗

پروژه اولیه را از اینجا دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

ساختار فایل‌های پروژه‌ی اولیه
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
Plain text

راه‌اندازی پروژه🔗

برای اجرای پروژه، باید NodeJS و npm را از قبل نصب کرده باشید.

  • ابتدا پروژه‌ی اولیه را دانلود و از حالت فشرده خارج کنید.
  • در پوشه‌ی like-snappfood ، دستور npm install را برای نصب نیازمندی‌ها اجرا کنید.
  • در همین پوشه، دستور npm start را برای راه‌اندازی پروژه اجرا کنید.
  • پس از انجام موفق این مراحل، با مراجعه به آدرس http://localhost:3000/ می‌توانید نتیجه را ببینید.

جزئیات🔗

طراحی state برنامه بدین صورت است:

{
    cart: {
        addedIds: Array(productIds),
        money: Int,
        quantityById: Object(productId: quantity)
    },
    products{
        byId: Object(productId: product),
        visibleIds: Array(productIds)
    }
}
JavaScript
  • 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 در فایل ارسالی نباشد.

شلمرود


سال‌ها پیش حسنی که دست از تنبلی برداشته بود تصمیم گرفت در کار مزرعه به پدرش کمک کند.

حسنی در ده شلمرود

اکنون که حسنی به توسعه‌ی Front-end علاقه‌مند شده، تصمیم گرفته به یاد گذشته و مزرعه‌ی پدری یک بازی با React طراحی کند. او در میانه‌ی کار به شلمرود رفته و پروژه‌ی نیمه‌کاره را به شما سپرده تا آن را کامل کنید.

بازی شلمرود - ۱

در این بازی، مزرعه به شکل یک جدول از نهرهاست و هدف رساندن آب به همه‌ی نهرهای مزرعه است. یکی از نهرها منبع آب است. با کلیک روی هر نهر، آن نهر ۹۰ درجه در جهت ساعتگرد می‌چرخد. بازی تعدادی مرحله دارد و با حل یک مرحله، (در صورتی که در آخرین مرحله نباشیم) دکمه‌ی رفتن به مرحله‌ی بعد فعال می‌شود.

برای حل یک مرحله باید نهرها در وضعیتی قرار بگیرند که:

  1. آب به همه‌ی نهرها برسد.
  2. آب هدر نرود. به عبارت دیگر همه‌ی نهرها به هم متصل شوند.

مثلاً در شکل زیر هنوز بازی حل نشده است و برای حل آن باید ۳ بار روی نهر وسط کلیک کنیم.

بازی شلمرود - ۲

مثالی از بازی را در شکل زیر می‌بینید. در این مثال بازی تنها ۲ مرحله دارد.

بازی شلمرود - ۳

پروژه اولیه🔗

پروژه اولیه را از اینجا دانلود کنید.

ساختار فایل‌های پروژه‌ی اولیه
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
Plain text

راه‌اندازی پروژه🔗

برای اجرای پروژه، باید NodeJS و npm (یا pnpm) را از قبل نصب کرده باشید.

  • در پوشه‌ی shalamrood ، دستور npm install را برای نصب نیازمندی‌ها اجرا کنید.
    • نکته: برای نصب سریع‌تر از pnpm install استفاده کنید.
  • در همین پوشه، دستور npm start را برای راه‌اندازی پروژه اجرا کنید.
  • با مراجعه به http://localhost:3000/ می‌توانید نتیجه را ببینید.
  • برای اجرای تست‌های نمونه npm test را اجرا کنید.

جزئیات🔗

حسنی برای پروژه تعدادی مؤلفه تعریف کرده که در جدول زیر مشاهده می‌کنید. او با خواندن مقاله‌ی Lifting State Up تصمیم گرفته حالت بازی را در بالاترین مؤلفه یعنی App قرار دهد.

مؤلفه توضیحات
App مؤلفه‌ی اصلی بازی است و حالت بازی در آن قرار دارد.
Menu مؤلفه‌ی بدون حالت برای نمایش عدد مرحله و دکمه‌های «مرحله بعد» و «شروع مجدد»
Board مؤلفه‌ی بدون حالت برای نمایش نهرها
Cell مؤلفه‌ی بدون حالت برای نمایش یک نهر

نهرها انواع زیر را دارند:

انواع نهر در شلمرود

حالت بازی (حالت مؤلفه‌ی App) به صورت زیر است.

{
    rows: 3,
    cols: 3,
    source: 8,
    level: 0,
    cells: [
        {
            type: "L",
            rotate: 3,
            active: false
        },
        {
            type: "T",
            rotate: 2,
            active: true
        },
        ...
    ]
}
JavaScript

همان‌طور که مشخص است، تعداد سطرها و ستون‌ها، شماره‌ی نهر منبع آب (source)، شماره‌ی مرحله‌ای که در آن قرار داریم و وضعیت نهرها در حالت قرار می‌گیرد.

  • شماره‌ی مرحله در state از صفر شروع می‌شود اما هنگام نمایش از یک شروع می‌شود.
  • وضعیت نهرها به صورت سطر به سطر از چپ به راست در آرایه‌ی cells قرار می‌گیرد.
  • مقدار rotate برای هر نهر عددی بین ۰ تا ۳ است و نشان می‌دهد نسبت به وضعیت اصلی نهر که در شکل بالا می‌بینید چند بار چرخیده است.
  • مقدار active برای هر نهر نشان می‌دهد که آب به آن نهر رسیده یا خیر. بنابراین مقدار active برای منبع آب باید همواره true باشد.

مواردی که باید پیاده‌سازی کنید:

۱. نمایش اولیه🔗

در نمایش اولیه‌ی مرحله‌ی اول بازی، باید منبع آب و همه‌ی نهرهایی که آب به آن‌ها می‌رسد فعال باشند (active: true). دکمه‌ی رفتن به مرحله‌ی بعد باید غیرفعال باشد (با صفت disabled).

۲. عملکرد صحیح کلیک روی نهرها🔗

با کلیک روی هر نهر، باید حالت به نحوی مناسب تغییر کند تا آن نهر ۹۰ درجه بچرخد و آب نیز بر اساس وضعیت جدید نهرها به آن‌ها برسد.

۳. عملکرد صحیح دکمه‌ها🔗

  • در هر مرحله‌ای که هستیم، کلیک بر روی دکمه‌ی شروع مجدد باید آن مرحله را از ابتدا شروع کند.
  • دکمه‌ی مرحله‌ی بعد باید در صورتی که مرحله‌ی فعلی حل شده و مرحله‌ی بعدی نیز وجود دارد فعال باشد و در غیر این صورت غیرفعال باشد.
  • در صورت حل شدن مرحله، دکمه‌ی مرحله‌ی بعد باید بازی را به مرحله‌ی بعد ببرد (عدد مرحله و نهرها باید به‌روز شود).

نکات🔗

  • می‌توانید در صورت نیاز داده‌های دیگری نیز در حالت مؤلفه ذخیره کنید. اما مجاز به تغییر ساختار داده‌های فعلی نیستید.
  • شما تنها مجاز به اعمال تغییر در فایل‌های App.js، Menu.js، Board.js و Cell.js هستید.
  • پس از اعمال تغییرات، پروژه را Zip کرده و ارسال کنید. دقت کنید که پوشه‌ی node_modules در فایل ارسالی نباشد.