اسلایدر محصولات


پروژه اولیه🔗

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

ساختار پروژه
product-slider
├── assets
│   ├── css
│   │   ├── index.css
│   │   ├── productCard.css
│   │   └── productSlider.css
│   ├── font
│   │   └── Vazir.ttf
│   └── images
│       ├── 01.jpg
│       ├── 02.jpg
│       ├── 03.jpg
│       ├── 04.jpg
│       ├── 05.jpg
│       ├── 06.jpg
│       ├── favicon.ico
│       ├── next.png
│       └── previous.png
├── cypress
│   ├── fixtures
│   │   └── example.json
│   ├── plugins
│   │   └── index.js
│   └── support
│       ├── commands.js
│       └── index.js
├── data
│   └── index.js
├── utils
│   └── number.js
├── cypress.json
├── index.html
├── package.json
└── script.js
Plain text

جزئیات🔗

ظاهر کلی برنامه به‌این صورت است:

ظاهر برنامه

فرض کنید که می‌خواهیم برای صفحه‌ی اصلی وب‌سایت یک اسلایدر یا نمایش‌دهنده‌ی محصول ایجاد کنیم. این اسلایدر باید در لحظه از بین محصولات یک محصول را به صورت تصادفی به کاربر نمایش دهد.

مواردی که باید در این سوال رعایت کنید:🔗

  • مدت زمان نمایش هر اسلاید ۴ ثانیه است.
  • بعد از گذشتن ۴ ثانیه محصول تصادفی بعدی نمایش داده می‌شود.
  • کاربر باید بتواند توسط دکمه های مربوطه، اسلاید قبل و بعد را مشاهده کند.
  • انتخاب و نمایش محصول جدید باید به صورت تصادفی باشد و نباید شامل دو محصول آخر که نمایش داده شده است، باشد.

تغییرات لازم برای هر فایل:🔗

  • فایل script.js: موارد خواسته شده باید در این فایل قرار داده شوند.
  • در فایل فوق سه تابع برای شما در نظر گرفته شده است که باید آن‌ها را تکمیل کنید. ​

نکات🔗

  • فرض کنید حداقل تعداد محصولات ۴ عدد خواهد بود.
  • شما تنها مجاز به اعمال تغییرات در فایل‌ script.js هستید.
  • برای ارسال پاسخ فقط فایل script.js ارسال کنید.

خلبان زبل


پروژه اولیه🔗

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

ساختار پروژه
khalabane-zebel
├── assets
│   └── images
│       └── favicon.ico
├── cypress
│   ├── fixtures
│   │   └── example.json
│   ├── plugins
│   │   └── index.js
│   └── support
│       ├── commands.js
│       └── index.js
├── styles
│   └── app.css
├── cypress.json
├── index.html
├── package.json
└── script.js
Plain text

جزئیات🔗

ظاهر کلی برنامه به‌این صورت است:

ظاهر برنامه

در این سوال می‌خواهیم یک بازی طراحی کنیم تا خلبان بتواند با کمک آن، توانایی بینایی خود را به چالش بکشد.
طراحی این بازی این‌گونه است که یک رنگ به عنوان صورت سوال و چهار رنگ هم به عنوان گزینه‌ها قرار می‌گیرند. حال خلبان باید با استفاده از کشیدن رنگ‌ها و رهاسازی آن‌ها در بخش‌های darker و lighter، مشخص کند که کدام رنگ‌ها تیره‌تر و کدام رنگ‌ها روشن‌تر از رنگ اصلی یا همان رنگ‌ سوال می‌باشند.

مواردی که باید در این سوال رعایت کنید:🔗

  • خلبان باید بتواند از بخش .optionsBox دایره‌های رنگی را بکشد (drag) و در بخش .lighterBox یا .darkerBox رها کند (drop).
  • خلبان ممکن است اشتباه کند و دایره‌ها در قسمت نادرست قرار دهد. به‌همین دلیل خلبان می‌تواند در هر شرایطی دایره‌ها را بین قسمت‌های .lighterBox و .darkerBox جابه‌جا کند. (عمل drag and drop)
  • امکان برگشتن دایره‌های قرار داده شده در قسمت‌های .lighterBox و .darkerBox به قسمت .optionsBox وجود ندارد.
  • هنگامی که خلبان تمام دایره‌ها را در .lighterBox و .darkerBox قرار داد، دکمه ثبت باید فعال شود.
  • شما باید تابع handleDragAndDrop را تکمیل کنید.
  • دایره‌های رنگی در متغیر answerBoxes قرار داده شده است.

تغییرات لازم برای هر فایل:🔗

  • فایل script.js: موارد خواسته‌شده باید در این فایل قرار داده شوند.

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل‌ script.js هستید.
  • برای ارسال پاسخ فقط فایل script.js ارسال کنید.
  • قسمتی از کد مورد نیاز برای عمل drag and drop در پروژه اولیه آمده است. برای اطلاعات بیشتر می‌توانید به این لینک مراجعه کنید.

هوک درخواست‌دهنده


پروژه اولیه🔗

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

ساختار پروژه
use-page-data
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── hooks
│   │   └── usePageData.js
│   ├── App.js
│   ├── index.css
│   └── index.js
└── package.json
Plain text
راه‌اندازی پروژه

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

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

جزئیات🔗

ظاهر کلی برنامه به‌این صورت است: ​ ظاهر برنامه ​ از آن‌جایی که تعداد محصولات دیجی‌کالا در حال زیاد شدن است، ساخت Custom Hook به یک بخش جدانشدنی از پروژه‌ها تبدیل شده است. ساختار api ها در دیجی‌کالا در تمام پروژه‌ها رعایت شده است. این موضوع باعث می‌شود ساخت یک Custom Hook برای ارسال درخواست‌ها به سرور بسیار مفید باشد. در این سوال از شما می‌خواهیم یک Custom Hook به این منظور پیاده‌سازی کنید.

این هوک باید ورودی‌های زیر را دریافت کند: ​

{
  "url": string,
  "fireOnLoad": boolean,
  "successCallback": (data) => void,
  "failedCallback": () => void,
}
JSON
  • url: این پارامتر آدرس api را مشخص می‌کند. به‌عبارتی دیگر شما باید به این آدرس درخواست را ارسال کنید.
  • fireOnLoad: این پارامتر مشخص می‌کند که آیا درخواست در هنگام ایجاد کامپوننت (mount) ارسال شود یا خیر.
  • successCallback: این پارامتر یک callback function ،است و در‌صورتی که درخواست با موفقیت تمام شد باید صدا زده شود. پارامتر ورودی این تابع، پاسخ سرور است.
  • failedCallback: این پارامتر یک callback function است و در‌صورتی که درخواست ناموفق بود، باید صدا زده شود.

خروجی هوک باید به شکل زیر باشد: ​

{
  "pending": boolean,
  "hasError": boolean,
  "data": any,
  "request": () => Promise<any>,
}
JSON
  • pending: نشان‌دهنده‌ی آن است که درخواست به سرور فرستاده شده است ولی هنوز پاسخی از سرور دریافت نشده است.
  • hasError: نشان‌دهنده‌ی ناموفق بودن درخواست ارسالی است.
  • request: یک تابع async برای ارسال درخواست است. این تابع بخش اصلی هوک است. در صورت موفق‌بودن درخواست این تابع باید پاسخ را برگرداند (resolve). این تابع را می‌توان به صورت جداگانه نیز صدا کرد.
  • data : پاسخ سرور در این فیلد قرار داده می‌شود.

هم‌چنین این هوک باید قابلیت کش‌کردن درخواست‌ها را درصورت موفقیت‌آمیز بودن ریکوئست داشته باشد؛ به‌این‌صورت که برای هر url وضعیت درخواست را ذخیره کند و در درخواست‌های بعدی به آن url از کش بخواند و درخواست جدیدی ارسال نکند.​ به‌عنوان مثال اگر هوک در چند جای مختلف استفاده شود یا اگر متد request چند بار برای یک url فراخوانی شود تنها یک ریکوئست به url داده شده زده می‌شود و پاسخ سرور برای بقیه ریکوئست‌ها با url یکسان استفاده می‌گردد. ساختار کش را میتوانید هرطور که خواستید پیاده سازی کنید به طور مثال این ساختار میتواند برای هر url به شکل زیر باشد:​

{
  "hasError": boolean,
  "result": any,
}
JSON

مواردی که باید در این سوال رعایت کنید:🔗

  • در صورتی که مقدار fireOnLoad برابر true باشد، باید تابع request در هنگام mount شدن کامپوننت صدا زده شود.
  • درصورت وجود یک url در کش، درخواست جدیدی به آن url نباید ارسال شود.
  • شرایط گفته شده باید برای هنگامی که url در کش موجود است نیز برقرار باشد.
  • ‌ باید بتوان توسط تابع request به پاسخ سرور پس از resolve شدن دسترسی داشت.

تغییرات لازم برای هر فایل:🔗

  • فایل usePageData.js: موارد خواسته شده باید در این فایل قرار داده شوند. ​

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل‌ usePageData.js هستید.
  • فرض کنید تمام درخواست‌های GET می‌باشند.
  • برای ارسال پاسخ فقط فایل usePageData.js ارسال کنید.

پیندو


پروژه اولیه🔗

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

ساختار پروژه
pindo
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   └── logo512.png
├── src
│   ├── assets
│   │   └── font
│   │       └── Vazir.ttf
│   ├── components
│   │   ├── Button
│   │   │   ├── Button.css
│   │   │   └── index.jsx
│   │   ├── Checkbox
│   │   │   └── index.jsx
│   │   ├── CitySelector
│   │   │   ├── CitySelectorItem.jsx
│   │   │   └── index.jsx
│   │   ├── Dropdown
│   │   │   └── index.jsx
│   │   ├── Error
│   │   │   └── index.jsx
│   │   ├── TextInput
│   │   │   └── index.jsx
│   │   ├── Textarea
│   │   │   └── index.jsx
│   │   └── FormItem.jsx
│   ├── constants
│   │   ├── Errors.js
│   │   └── FormType.js
│   ├── data
│   │   ├── cities.js
│   │   └── formData.js
│   ├── App.css
│   ├── App.jsx
│   ├── index.css
│   └── index.js
└── package.json
Plain text
راه‌اندازی پروژه

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

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

جزئیات🔗

ظاهر کلی برنامه به‌این صورت است:

ظاهر برنامه

یکی از قسمت‌های اصلی پروژه پیندو ایجاد آگهی است. کاربران در دسته‌بندی‌های مختلفی می‌توانند برای کالای خود آگهی ایجاد کنند. برای مثال فرم ایجاد آگهی برای گوشی موبایل با ظروف آشپزخانه متفاوت است. به‌ همین جهت فرم ایجاد آگهی باید به صورت داینامیک باشد. در این سوال از شما می‌خواهیم این فرم‌های داینامیک را بسازید.

اِلِمان‌های فرم در یک آرایه قرار دارد. ساختار این آرایه به شکل زیر است:

{
  "type": string,
  "required": boolean | undefined,
  "name": string,
  "label": string,
  "options": { "title": string, "value": number }[],
  "dependency": {
    "show": { "name": string, "value": string | boolean | number },
    "required": { "name": string, "value": string | boolean | number },
  } | undefined,
}
JSON

فیلد type🔗

این فیلد نشان‌دهنده‌ی نوع اِلمان است.

هر المان فرم می‌تواند یکی از مقادیر type زیر را داشته باشد:

const FormType = {
  TEXT: "text",
  DROPDOWN: "dropdown",
  TEXTAREA: "textarea",
  CHECKBOX: "checkbox",
  CITY: "city",
};
JavaScript

فیلد required🔗

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

فیلد name🔗

این فیلد نشان‌دهنده‌ی کلید اصلی آن المان است. در هنگام ساخت داده‌های ورودی کاربر، مقدار کلید برابر این فیلد است.

فیلد label🔗

این فیلد مشخص‌کننده‌ی برچسب (لیبل) المان است.

فیلد options🔗

در صورتی که type یک المان برابر FormType.DROPDOWN باشد، مقادیری قابل انتخاب در فرم select در این فیلد قرار می‌گیرد.

فیلد dependency🔗

هر المان می‌تواند به المان دیگری وابستگی داشته باشد. این موضوع در این فیلد مشخص می‌شود. در صورتی که این فیلد وجود نداشت، به این معنا است که این فیلد به فیلد دیگری وابستگی ندارد. وابستگی به دو شکل وجود دارد:

  • وابستگی show: به این معنا است که نمایش این فیلد به مقدار یک فیلد دیگر وابسته است.
  • وابستگی required: به این معنا است که اجباری بودن این فیلد به مقدار یک فیلد دیگر وابسته است.

هر کدام از این وابستگی‌ها به شکل زیر مشخص می‌شوند:

{ "name": string, "value": string | boolean | number }
JSON

که name نشان‌دهنده‌ی فیلدی است که به آن وابسته است و value نشان‌دهنده‌ی شرط وابستگی است. در صورتی که مقدار فیلد name برابر value بود، شرط وابستگی برقرار است.

برای مثال در داده‌‌ی زیر فیلد productIssues به فیلد productStatus وابسته است. در صورتی که مقدار انتخابی در productStatus برابر 4 باشد (یعنی مقدار انتخابی خراب باشد)، این فیلد باید (productIssues) نمایش داده شود. هم‌چنین اجباری‌بودن فیلد city به مقدار فیلد delivery بستگی دارد و مقدار این فیلد باید true باشد. دقت کنید این فیلد باید نمایش داده شود ولی اجباری‌بودن آن به فیلد دیگری بستگی دارد.

[
  {
    "type": "dropdown",
    "name": "productStatus",
    "label": "وضعیت کالا",
    "options": [
      { "title": "نو", "value": 1 },
      { "title": "در حد نو", "value": 2 },
      { "title": "دست دوم", "value": 3 },
      { "title": "خراب", "value": 4 },
    ],
  },
  {
    "type": "textarea",
    "name": "productIssues",
    "label": "مشکلات کالا",
    "dependency": {
      "show": { "name": "productStatus", "value": 4 },
    },
  },
  {
    "type": "checkbox",
    "name": "delivery",
    "label": "از سیستم دلیوری استفاده خواهم کرد",
  },
  {
    "type": "city",
    "name": "cityId",
    "label": "محل آگهی",
    "dependency": {
      "required": { "name": "delivery", "value": true },
    },
  },
];
JSON

مواردی که باید در این سوال رعایت کنید:🔗

  • شما باید برنامه‌ای بنویسید که لیست فیلد‌ها را دریافت کند و به این شکل ساختاری نمایش دهد.
  • فرم نهایی در صورتی باید submit شود که تمام شرایط لازم در آن رعایت شده باشد (تمام فیلدهای اجباری وارد شده باشند).
  • مقادیر وارد شده باید به تابع onSubmit پاس داده شود. (این تابع به شکل prop به کامپوننت داده می‌شود)
  • در صورتی که یک فیلد اجباری پر نشده بود، باید برای آن فیلد خطا نمایش داده شود (کاپوننت آن آورده شده است و فقط لازم است برحسب شرایط از آن استفاده کنید).
  • در صورتی که یک فیلد غیراجباری پر نشده بود، باید برای آن فیلد مقدار undefiend به تابع onSubmit فرستاده شود.

تغییرات لازم برای هر فایل:🔗

  • فایل App.jsx: منطق اصلی کد شما در این فایل قرار می‌گیرد. در این فایل شما props را به‌عنوان ورودی می‌گیرید.
  • onSubmit: زمانی که فرم بدون خطا بود، به این تابع مقادیر وارد شده را به‌عنوان پارامتر ورودی بفرستید.
  • fields: فیلد‌های فرم در این prop قرار می‌گیرد.
  • فایل FormItem.jsx: در این کامپوننت شما براساس type هر المان باید از یکی کامپوننت‌های آورده شده، استفاده کنید.

شما لازم است براساس هر آیتم در fields از این کامپوننت استفاده کنید.

نکات🔗

  • حتما از کامپوننت‌های داخل پروژه استفاده شود، در غیر این صورت نمره سوال را نخواهید گرفت.
  • شما تنها مجاز به اعمال تغییرات در فایل‌های App.jsx و FormItem.jsx و package.json هستید.
  • به کامنت‌های داخل فایل‌ها دقت کنید.
  • استفاده از کتابخانه‌های خارجی مجاز است. (در پروژه اولیه کتاب‌خانه‌ی react-hook-form قرار داده شده است)
  • برای ارسال پاسخ کل پروژه را zip کرده و ارسال کنید. دقت کنید که پوشه‌ی node_modules در فایل ارسالی نباشد.

کامنت‌های تودرتو


پروژه اولیه🔗

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

ساختار پروژه
nested-comments
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── components
│   │   ├── CommentBox
│   │   │   ├── _styles.scss
│   │   │   └── index.jsx
│   │   └── CommentList
│   │       ├── _styles.scss
│   │       └── index.jsx
│   ├── data
│   │   └── data.json
│   ├── App.jsx
│   ├── index.css
│   └── index.jsx
└── package.json
Plain text
راه‌اندازی پروژه

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

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

جزئیات🔗

ظاهر کلی برنامه بدین صورت است:

ظاهر برنامه

در این سوال می‌خواهیم لیست کامنت‌ها را به‌صورت درختی نمایش دهیم. لیست کامنت‌ها در پوشه data وجود دارد. ساختار هر کامنت به شکل زیر است:

{
  "id": string,
  "info": {
    "title": string,
    "description": string
  },
  "parentId": string | null,
  "user": {
    "firstName": string,
    "lastName": string
  }
}
JSON

در این ساختار هر کامنت دارای یک parentId است. اگر مقدار این فیلد null باشد به این معنا است که این کامنت دارای والد نیست. در غیر این صورت به ایدی والد این کامنت اشاره می‌کند.

برای مثال لیست کامنت‌ها به شکل زیر است:

[
  {
    "id": "id-1",
    "info": {
      "title": "title-1",
      "description": "description-1"
    },
    "parentId": null,
    "user": {
      "firstName": "firstName-1",
      "lastName": "lastName-1"
    }
  },
  {
    "id": "id-2",
    "info": {
      "title": "title-2",
      "description": "description-2"
    },
    "parentId": "id-1",
    "user": {
      "firstName": "firstName-2",
      "lastName": "lastName-2"
    }
  },
  {
    "id": "id-3",
    "info": {
      "title": "title-3",
      "description": "description-3"
    },
    "parentId": "id-2",
    "user": {
      "firstName": "firstName-3",
      "lastName": "lastName-3"
    }
  },
  {
    "id": "id-4",
    "info": {
      "title": "title-4",
      "description": "description-4"
    },
    "parentId": null,
    "user": {
      "firstName": "firstName-4",
      "lastName": "lastName-4"
    }
  },
  {
    "id": "id-5",
    "info": {
      "title": "title-5",
      "description": "description-5"
    },
    "parentId": "id-1",
    "user": {
      "firstName": "firstName-5",
      "lastName": "lastName-5"
    }
  },
]
JSON

این لیست باید به شکل زیر نشان داده شود:

├── id-1
│   ├── id-2
│   │    └── id-3
│   └── id-5
└── id-4
Plain text

در شکل بالا کامنت‌های id-1 و id-4 سطح صفر، id-2 و id-5 سطح یک و کامنت id-3 سطح دو هستند.

مواردی که باید در این سوال رعایت کنید:🔗

  • شما باید برنامه‌ای بنویسید که لیست کامنت‌ها را دریافت کند و به این شکل ساختاری نمایش دهد.
  • هر کامنت باید براساس سطحش در درخت دارای استایل margin-left باشد. برای مثال اگر کامنت در سطح صفر بود (یعنی والد است و والدی ندارد) باید دارای استایل margin-left: 0px باشد. اگر کامنت در سطح یک بود (دارای والد است) باید دارای استایل margin-left: 16px باشد. اگر کامنت در سطح دو بود (دارای والد است و والد آن خود والد دارد) باید دارای استایل margin-left: 32px باشد.
  • هر کامنت سطح صفری باید دارای کلاس root-comment باشد.
  • در صورتی که لیست کامنت‌ها خالی باشد، باید فقط کامپوننت EmptyList نمایش داده شود.

تغییرات لازم برای هر فایل:🔗

  • فایل App.jsx: شما لیست کامنت‌ها را در کامپوننت دریافت می‌کنید. قبل از فرستادن comments به کامپوننت CommentList باید ساختار مورد نظر را ایجاد کنید.
  • فایل CommentList.jsx: در این کامپوننت شما باید لیست کامنت‌ها را نمایش دهید. کلاس root-comment را برساس شرایط گفته شده در قسمت گفته شده قرار دهید. شما باید کامنت سطح صفر به‌همراه فرزندانش را در اینجا نشان دهید. در صورتی که فرزندی نداشت چیزی نباید نشان دهید.
  • فایل CommentBox.jsx: برای نمایش هر کامنت از این کامپوننت استفاده کنید. استایل margin-left و شرایط گفته شده باید در اینجا پیاده‌سازی شود.

نکات🔗

  • شما تنها مجاز به اعمال تغییرات در فایل‌های App.jsx و CommentList.jsx و CommentBox.jsx هستید.
  • به کامنت‌های داخل فایل‌ها دقت کنید.
  • مقدارهای data-testid پروژه اولیه نباید تغییر کنند.
  • برای قسمت استایل از inline-style استفاده کنید.
  • این استایل به اِلِمان با کلاس comment-box داخل فایل CommentBox.jsx داده شود.
  • برای ارسال پاسخ کل پروژه را zip کرده و ارسال کنید. دقت کنید که پوشه‌ی node_modules در فایل ارسالی نباشد.