# ব্যাংকিং অ্যাপ তৈরি করুন পার্ট ২: লগইন এবং রেজিস্ট্রেশন ফর্ম তৈরি করুন ## প্রি-লেকচার কুইজ [প্রি-লেকচার কুইজ](https://ff-quizzes.netlify.app/web/quiz/43) ### ভূমিকা প্রায় সব আধুনিক ওয়েব অ্যাপে, আপনি একটি অ্যাকাউন্ট তৈরি করতে পারেন যা আপনার ব্যক্তিগত জায়গা হিসেবে কাজ করবে। যেহেতু একাধিক ব্যবহারকারী একই সময়ে একটি ওয়েব অ্যাপ অ্যাক্সেস করতে পারে, তাই প্রতিটি ব্যবহারকারীর ব্যক্তিগত ডেটা আলাদাভাবে সংরক্ষণ করার এবং কোন তথ্য প্রদর্শন করতে হবে তা নির্বাচন করার একটি পদ্ধতি প্রয়োজন। আমরা [ব্যবহারকারীর পরিচয় নিরাপদে পরিচালনা](https://en.wikipedia.org/wiki/Authentication) করার বিষয়ে আলোচনা করব না কারণ এটি নিজেই একটি বিস্তৃত বিষয়, তবে আমরা নিশ্চিত করব যে প্রতিটি ব্যবহারকারী আমাদের অ্যাপে একটি (বা একাধিক) ব্যাংক অ্যাকাউন্ট তৈরি করতে সক্ষম। এই অংশে আমরা HTML ফর্ম ব্যবহার করে আমাদের ওয়েব অ্যাপে লগইন এবং রেজিস্ট্রেশন যোগ করব। আমরা দেখব কীভাবে প্রোগ্রাম্যাটিকভাবে সার্ভার API-তে ডেটা পাঠানো যায় এবং শেষ পর্যন্ত ব্যবহারকারীর ইনপুটের জন্য মৌলিক যাচাইকরণ নিয়ম সংজ্ঞায়িত করা যায়। ### পূর্বশর্ত এই পাঠের জন্য আপনাকে ওয়েব অ্যাপের [HTML টেমপ্লেট এবং রাউটিং](../1-template-route/README.md) সম্পন্ন করতে হবে। আপনাকে [Node.js](https://nodejs.org) ইনস্টল করতে হবে এবং [সার্ভার API চালাতে হবে](../api/README.md) স্থানীয়ভাবে যাতে আপনি অ্যাকাউন্ট তৈরি করার জন্য ডেটা পাঠাতে পারেন। **মনে রাখুন** আপনার দুটি টার্মিনাল একসাথে চালু থাকবে, যা নিচে তালিকাভুক্ত: 1. প্রধান ব্যাংক অ্যাপের জন্য যা আমরা [HTML টেমপ্লেট এবং রাউটিং](../1-template-route/README.md) পাঠে তৈরি করেছি। 2. [Bank APP server API](../api/README.md) এর জন্য যা আমরা উপরে সেটআপ করেছি। পাঠের বাকি অংশ অনুসরণ করতে আপনার দুটি সার্ভার চালু এবং চলমান থাকতে হবে। এগুলো বিভিন্ন পোর্টে (পোর্ট `3000` এবং পোর্ট `5000`) শুনছে, তাই সবকিছু ঠিকঠাক কাজ করবে। আপনি টার্মিনালে এই কমান্ডটি চালিয়ে সার্ভারটি সঠিকভাবে চলছে কিনা পরীক্ষা করতে পারেন: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## ফর্ম এবং কন্ট্রোল `
` উপাদানটি একটি HTML ডকুমেন্টের একটি অংশকে ঘিরে রাখে যেখানে ব্যবহারকারী ইন্টারেক্টিভ কন্ট্রোল ব্যবহার করে ডেটা ইনপুট এবং জমা দিতে পারে। ফর্মের মধ্যে বিভিন্ন ধরনের ব্যবহারকারী ইন্টারফেস (UI) কন্ট্রোল ব্যবহার করা যায়, যার মধ্যে সবচেয়ে সাধারণ `` এবং `
``` `value` অ্যাট্রিবিউট ব্যবহার করে আমরা একটি ইনপুটের জন্য ডিফল্ট মান সংজ্ঞায়িত করতে পারি। লক্ষ্য করুন যে `balance` এর ইনপুটে `number` টাইপ রয়েছে। এটি কি অন্য ইনপুটগুলোর চেয়ে আলাদা দেখাচ্ছে? এটি ইন্টারঅ্যাক্ট করে দেখুন। ✅ আপনি কি শুধুমাত্র কীবোর্ড ব্যবহার করে ফর্মগুলোতে নেভিগেট এবং ইন্টারঅ্যাক্ট করতে পারেন? আপনি কীভাবে এটি করবেন? ## সার্ভারে ডেটা জমা দেওয়া এখন আমাদের একটি কার্যকরী UI রয়েছে, পরবর্তী ধাপ হল ডেটা সার্ভারে পাঠানো। চলুন আমাদের বর্তমান কোড ব্যবহার করে একটি দ্রুত পরীক্ষা করি: যদি আপনি *Login* বা *Register* বোতামে ক্লিক করেন তাহলে কী ঘটে? আপনার ব্রাউজারের URL সেকশনে পরিবর্তন লক্ষ্য করেছেন? ![Register বোতামে ক্লিক করার পর ব্রাউজারের URL পরিবর্তনের স্ক্রিনশট](../../../../translated_images/click-register.e89a30bf0d4bc9ca867dc537c4cea679a7c26368bd790969082f524fed2355bc.bn.png) ডিফল্টভাবে `
` একটি [GET পদ্ধতি](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3) ব্যবহার করে বর্তমান সার্ভার URL-এ ফর্ম জমা দেয়, ফর্ম ডেটা সরাসরি URL-এ যোগ করে। তবে এই পদ্ধতির কিছু সীমাবদ্ধতা রয়েছে: - পাঠানো ডেটার আকার খুব সীমিত (প্রায় ২০০০ অক্ষর) - ডেটা URL-এ সরাসরি দৃশ্যমান (পাসওয়ার্ডের জন্য ভালো নয়) - এটি ফাইল আপলোডের সাথে কাজ করে না তাই আপনি এটি পরিবর্তন করে [POST পদ্ধতি](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5) ব্যবহার করতে পারেন যা ফর্ম ডেটা HTTP অনুরোধের বডিতে সার্ভারে পাঠায়, পূর্বের সীমাবদ্ধতাগুলো ছাড়াই। > যদিও POST ডেটা পাঠানোর জন্য সবচেয়ে সাধারণভাবে ব্যবহৃত পদ্ধতি, [কিছু নির্দিষ্ট পরিস্থিতিতে](https://www.w3.org/2001/tag/doc/whenToUseGet.html) GET পদ্ধতি ব্যবহার করা ভালো, যেমন একটি সার্চ ফিল্ড বাস্তবায়নের সময়। ### কাজ রেজিস্ট্রেশন ফর্মে `action` এবং `method` প্রপার্টি যোগ করুন: ```html ``` এখন আপনার নাম দিয়ে একটি নতুন অ্যাকাউন্ট রেজিস্টার করার চেষ্টা করুন। *Register* বোতামে ক্লিক করার পর আপনি এরকম কিছু দেখতে পাবেন: ![localhost:5000/api/accounts ঠিকানায় একটি ব্রাউজার উইন্ডো, যেখানে JSON স্ট্রিং সহ ব্যবহারকারীর ডেটা দেখানো হয়েছে](../../../../translated_images/form-post.61de4ca1b964d91a9e338416e19f218504dd0af5f762fbebabfe7ae80edf885f.bn.png) যদি সবকিছু ঠিকঠাক হয়, সার্ভার আপনার অনুরোধের উত্তর JSON রেসপন্স দিয়ে দেবে যেখানে তৈরি করা অ্যাকাউন্টের ডেটা থাকবে। ✅ একই নাম দিয়ে আবার রেজিস্টার করার চেষ্টা করুন। কী ঘটে? ## পেজ রিলোড ছাড়াই ডেটা জমা দেওয়া আপনি সম্ভবত লক্ষ্য করেছেন, আমরা যে পদ্ধতি ব্যবহার করেছি তাতে একটি ছোট সমস্যা রয়েছে: ফর্ম জমা দেওয়ার সময় আমরা আমাদের অ্যাপ থেকে বের হয়ে সার্ভার URL-এ ব্রাউজার রিডাইরেক্ট করি। আমরা আমাদের ওয়েব অ্যাপের সাথে সমস্ত পেজ রিলোড এড়াতে চাই, কারণ আমরা একটি [Single-page application (SPA)](https://en.wikipedia.org/wiki/Single-page_application) তৈরি করছি। পেজ রিলোড না করেই ফর্ম ডেটা সার্ভারে পাঠানোর জন্য আমাদের JavaScript কোড ব্যবহার করতে হবে। `` উপাদানের `action` প্রপার্টিতে একটি URL দেওয়ার পরিবর্তে, আপনি `javascript:` স্ট্রিং দিয়ে শুরু করে যেকোনো JavaScript কোড ব্যবহার করতে পারেন কাস্টম অ্যাকশন সম্পাদন করতে। এটি ব্যবহার করার অর্থ হল আপনাকে ব্রাউজার দ্বারা স্বয়ংক্রিয়ভাবে সম্পাদিত কিছু কাজ বাস্তবায়ন করতে হবে: - ফর্ম ডেটা পুনরুদ্ধার করা - ফর্ম ডেটাকে উপযুক্ত ফরম্যাটে রূপান্তর এবং এনকোড করা - HTTP অনুরোধ তৈরি করা এবং এটি সার্ভারে পাঠানো ### কাজ রেজিস্ট্রেশন ফর্মের `action` পরিবর্তন করুন: ```html ``` `app.js` খুলুন এবং `register` নামে একটি নতুন ফাংশন যোগ করুন: ```js function register() { const registerForm = document.getElementById('registerForm'); const formData = new FormData(registerForm); const data = Object.fromEntries(formData); const jsonData = JSON.stringify(data); } ``` এখানে আমরা `getElementById()` ব্যবহার করে ফর্ম উপাদানটি পুনরুদ্ধার করি এবং [`FormData`](https://developer.mozilla.org/docs/Web/API/FormData) হেল্পার ব্যবহার করে ফর্ম কন্ট্রোল থেকে মানগুলো কী/মান জোড়া হিসেবে বের করি। তারপর আমরা ডেটাকে একটি নিয়মিত অবজেক্টে রূপান্তর করি [`Object.fromEntries()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) ব্যবহার করে এবং শেষ পর্যন্ত ডেটাকে [JSON](https://www.json.org/json-en.html) এ সিরিয়ালাইজ করি, যা ওয়েবে ডেটা বিনিময়ের জন্য সাধারণত ব্যবহৃত একটি ফরম্যাট। ডেটা এখন সার্ভারে পাঠানোর জন্য প্রস্তুত। `createAccount` নামে একটি নতুন ফাংশন তৈরি করুন: ```js async function createAccount(account) { try { const response = await fetch('//localhost:5000/api/accounts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: account }); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` এই ফাংশনটি কী করছে? প্রথমে, এখানে `async` কীওয়ার্ড লক্ষ্য করুন। এর অর্থ হল ফাংশনটি এমন কোড ধারণ করে যা [**অ্যাসিঙ্ক্রোনাসভাবে**](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function) কার্যকর হবে। যখন `await` কীওয়ার্ডের সাথে ব্যবহার করা হয়, এটি অ্যাসিঙ্ক্রোনাস কোড কার্যকর হওয়ার জন্য অপেক্ষা করতে দেয় - যেমন এখানে সার্ভারের উত্তর পাওয়ার জন্য অপেক্ষা করা - তারপর চালিয়ে যায়। `fetch()` API ব্যবহার করে আমরা JSON ডেটা সার্ভারে পাঠাই। এই পদ্ধতি দুটি প্যারামিটার নেয়: - সার্ভারের URL, তাই আমরা এখানে `//localhost:5000/api/accounts` ব্যবহার করি। - অনুরোধের সেটিংস। এখানে আমরা পদ্ধতিকে `POST` সেট করি এবং অনুরোধের জন্য `body` প্রদান করি। যেহেতু আমরা JSON ডেটা সার্ভারে পাঠাচ্ছি, তাই আমাদের `Content-Type` হেডারকে `application/json` সেট করতে হবে যাতে সার্ভার বিষয়বস্তুটি কীভাবে ব্যাখ্যা করবে তা জানে। যেহেতু সার্ভার অনুরোধের উত্তর JSON দিয়ে দেবে, আমরা `await response.json()` ব্যবহার করে JSON বিষয়বস্তু পার্স করতে পারি এবং ফলাফল অবজেক্টটি ফেরত দিতে পারি। লক্ষ্য করুন যে এই পদ্ধতিটি অ্যাসিঙ্ক্রোনাস, তাই আমরা এখানে `await` কীওয়ার্ড ব্যবহার করি যাতে পার্সিংয়ের সময় কোনো ত্রুটি ধরা পড়ে। এখন `register` ফাংশনে কিছু কোড যোগ করুন `createAccount()` কল করার জন্য: ```js const result = await createAccount(jsonData); ``` যেহেতু আমরা এখানে `await` কীওয়ার্ড ব্যবহার করছি, আমাদের `register` ফাংশনের আগে `async` কীওয়ার্ড যোগ করতে হবে: ```js async function register() { ``` শেষে, ফলাফল পরীক্ষা করার জন্য কিছু লগ যোগ করুন। চূড়ান্ত ফাংশনটি এরকম হওয়া উচিত: ```js async function register() { const registerForm = document.getElementById('registerForm'); const formData = new FormData(registerForm); const jsonData = JSON.stringify(Object.fromEntries(formData)); const result = await createAccount(jsonData); if (result.error) { return console.log('An error occurred:', result.error); } console.log('Account created!', result); } ``` এটি একটু দীর্ঘ ছিল কিন্তু আমরা শেষ পর্যন্ত পৌঁছেছি! যদি আপনি আপনার [ব্রাউজার ডেভেলপার টুল](https://developer.mozilla.org/docs/Learn/Common_questions/What_are_browser_developer_tools) খুলেন এবং একটি নতুন অ্যাকাউন্ট রেজিস্টার করার চেষ্টা করেন, আপনি ওয়েব পেজে কোনো পরিবর্তন দেখতে পাবেন না তবে কনসোলে একটি বার্তা প্রদর্শিত হবে যা নিশ্চিত করবে যে সবকিছু কাজ করছে। ![ব্রাউজার কনসোলে লগ বার্তা দেখানোর স্ক্রিনশট](../../../../translated_images/browser-console.efaf0b51aaaf67782a29e1a0bb32cc063f189b18e894eb5926e02f1abe864ec2.bn.png) ✅ আপনি কি মনে করেন ডেটা সার্ভারে নিরাপদে পাঠানো হচ্ছে? যদি কেউ অনুরোধটি আটকাতে সক্ষম হয় তাহলে কী হবে? [HTTPS](https://en.wikipedia.org/wiki/HTTPS) সম্পর্কে পড়ুন যাতে নিরাপদ ডেটা যোগাযোগ সম্পর্কে আরও জানতে পারেন। ## ডেটা যাচাইকরণ যদি আপনি প্রথমে একটি username সেট না করে একটি নতুন অ্যাকাউন্ট রেজিস্টার করার চেষ্টা করেন, আপনি দেখতে পাবেন যে সার্ভার [400 (Bad Request)](https://developer.mozilla.org/docs/Web/HTTP/Status/400#:~:text=The%20HyperText%20Transfer%20Protocol%20(HTTP,%2C%20or%20deceptive%20request%20routing).) স্ট্যাটাস কোড সহ একটি ত্রুটি ফেরত দেয়। সার্ভারে ডেটা পাঠানোর আগে এটি যাচাই করা একটি ভালো অভ্যাস, যখন সম্ভব, যাতে আপনি একটি বৈধ অনুরোধ পাঠান। HTML5 ফর্ম কন্ট্রোল বিভিন্ন অ্যাট্রিবিউট ব্যবহার করে বিল্ট-ইন যাচাইকরণ প্রদান করে: - `required`: ফিল্ডটি পূরণ করতে হবে, অন্যথায় ফর্ম জমা দেওয়া যাবে না। - `minlength` এবং `maxlength`: টেক্সট ফিল্ডে অক্ষরের সর্বনিম্ন এবং সর্বাধিক সংখ্যা সংজ্ঞায়িত করে। - `min` এবং `max`: সংখ্যাসূচক ফিল্ডের সর্বনিম্ন এবং সর্বাধিক মান সংজ্ঞায়িত করে। - `type`: প্রত্যাশিত ডেটার ধরণ সংজ্ঞায়িত করে, যেমন `number`, `email`, `file` বা [অন্যান্য বিল্ট-ইন টাইপ](https://developer.mozilla.org/docs/Web/HTML/Element/input)। এই অ্যাট্রিবিউটটি ফর্ম কন্ট্রোলের ভিজ্যুয়াল রেন্ডারিংও পরিবর্তন করতে পারে। - `pattern`: একটি [রেগুলার এক্সপ্রেশন](https://developer.mozilla.org/docs/Web/JavaScript/Guide/Regular_Expressions) প্যাটার্ন সংজ্ঞায়িত করতে দেয় যা পরীক্ষা করে ইনপুটকৃত ডেটা বৈধ কিনা। পরামর্শ: আপনি আপনার ফর্ম কন্ট্রোলগুলোর চেহারা কাস্টমাইজ করতে পারেন, সেগুলো বৈধ কিনা বা অবৈধ কিনা তা নির্ভর করে, `:valid` এবং `:invalid` CSS পসুডো-ক্লাস ব্যবহার করে। ### কাজ একটি বৈধ নতুন অ্যাকাউন্ট তৈরি করতে দুটি প্রয়োজনীয় ক্ষেত্র রয়েছে: ব্যবহারকারীর নাম এবং মুদ্রা। বাকি ক্ষেত্রগুলো ঐচ্ছিক। ফর্মের HTML আপডেট করুন, `required` অ্যাট্রিবিউট এবং ক্ষেত্রের লেবেলে টেক্সট ব্যবহার করে যাতে: ```html ... ``` যদিও এই নির্দিষ্ট সার্ভার ইমপ্লিমেন্টেশন ক্ষেত্রগুলোর সর্বোচ্চ দৈর্ঘ্যের উপর নির্দিষ্ট সীমা আরোপ করে না, তবুও ব্যবহারকারীর টেক্সট এন্ট্রির জন্য যুক্তিসঙ্গত সীমা নির্ধারণ করা সবসময়ই একটি ভালো অভ্যাস। টেক্সট ক্ষেত্রগুলোতে একটি `maxlength` অ্যাট্রিবিউট যোগ করুন: ```html ... ... ``` এখন যদি আপনি *Register* বোতামটি চাপেন এবং কোনো ক্ষেত্র আমাদের সংজ্ঞায়িত করা ভ্যালিডেশন নিয়ম মেনে না চলে, তাহলে আপনি এরকম কিছু দেখতে পাবেন: ![ফর্ম জমা দেওয়ার চেষ্টা করার সময় ভ্যালিডেশন ত্রুটি দেখানো একটি স্ক্রিনশট](../../../../translated_images/validation-error.8bd23e98d416c22f80076d04829a4bb718e0e550fd622862ef59008ccf0d5dce.bn.png) এই ধরনের ভ্যালিডেশন, যা কোনো ডেটা সার্ভারে পাঠানোর *আগে* সম্পন্ন হয়, তাকে **ক্লায়েন্ট-সাইড** ভ্যালিডেশন বলা হয়। তবে মনে রাখবেন, সব চেক করা সবসময় ডেটা না পাঠিয়েও সম্ভব নয়। উদাহরণস্বরূপ, আমরা এখানে চেক করতে পারি না যে একই ব্যবহারকারীর নাম দিয়ে একটি অ্যাকাউন্ট ইতিমধ্যেই বিদ্যমান কিনা, সার্ভারে একটি অনুরোধ না পাঠিয়ে। অতিরিক্ত ভ্যালিডেশন যা সার্ভারে সম্পন্ন হয়, তাকে **সার্ভার-সাইড** ভ্যালিডেশন বলা হয়। সাধারণত উভয়ই বাস্তবায়ন করা প্রয়োজন, এবং ক্লায়েন্ট-সাইড ভ্যালিডেশন ব্যবহারকারীর অভিজ্ঞতা উন্নত করে তাৎক্ষণিক প্রতিক্রিয়া প্রদান করে, তবে সার্ভার-সাইড ভ্যালিডেশন অত্যন্ত গুরুত্বপূর্ণ যাতে আপনি যে ব্যবহারকারীর ডেটা পরিচালনা করছেন তা সঠিক এবং নিরাপদ হয়। --- ## 🚀 চ্যালেঞ্জ যদি ব্যবহারকারী ইতিমধ্যেই বিদ্যমান থাকে, তাহলে HTML-এ একটি ত্রুটির বার্তা দেখান। এখানে একটি উদাহরণ দেওয়া হলো, যেখানে কিছু স্টাইলিং করার পর চূড়ান্ত লগইন পৃষ্ঠাটি দেখতে এরকম হতে পারে: ![CSS স্টাইল যোগ করার পর লগইন পৃষ্ঠার একটি স্ক্রিনশট](../../../../translated_images/result.96ef01f607bf856aa9789078633e94a4f7664d912f235efce2657299becca483.bn.png) ## পোস্ট-লেকচার কুইজ [পোস্ট-লেকচার কুইজ](https://ff-quizzes.netlify.app/web/quiz/44) ## পর্যালোচনা ও স্ব-অধ্যয়ন ডেভেলপাররা তাদের ফর্ম তৈরির প্রচেষ্টায়, বিশেষ করে ভ্যালিডেশন কৌশলগুলোর ক্ষেত্রে, খুবই সৃজনশীল হয়ে উঠেছে। [CodePen](https://codepen.com) ঘেঁটে বিভিন্ন ফর্ম ফ্লো সম্পর্কে জানুন; আপনি কি কিছু আকর্ষণীয় এবং অনুপ্রেরণামূলক ফর্ম খুঁজে পেতে পারেন? ## অ্যাসাইনমেন্ট [আপনার ব্যাংক অ্যাপ স্টাইল করুন](assignment.md) **অস্বীকৃতি**: এই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসাধ্য সঠিকতার জন্য চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। মূল ভাষায় থাকা নথিটিকে প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যা হলে আমরা দায়ী থাকব না।