เขียนปุ่ม PINCODE ลอกแบบจาก Trezor


สวัสดีครับ… ครั้งนี้ผมอยากทำความเข้าใจเรื่องการ reuse compoennt จึงลองเขียนแบบมีปุ่มกดแล้วเรียกใช้งานเหมือนปุ่ม modal สิ่งที่ผมต้องการคือสามารถ import ไปใช้งานในหลายหน้า เหมือนกับ library โดยสิ่งที่ผมต้องทำความเข้าใจมากขึ้นระหว่างเขียนแบบนี้คือ การส่งค่าระหว่าง parent กับ child ครับ ในตอนนี้ผมก็จะเขียน useState แบบง่ายๆไปก่อน เพราะยังไม่มีความซับซ้อนอะไร ในการจัดการ state โดยทั่วไปแล้วก็อาจจะใช้ global state อย่าง Redux, Context API, Recoil หรืออื่นๆลองศึกษาและทำความเข้าใจการเขียนโปรแกรมได้มากขึ้น
จริงๆแล้วอยากเขียนให้เป็น library ลง npm แต่ว่ายังไม่ได้หาความรู้การเขียน library
Options
Name | Default | Description |
---|---|---|
max | 6 | กำหนดจำนวนสูงสุดของค่าที่ต้องการรับข้อมูล |
keypad | number | กำหนดปุ่มที่แสดงผลเป็นแบบต่างๆ |
random | false | กำหนดให้สุ่มตัวเลขของปุ่มกด |
onChangeValue | function | รับฟังก์ชั่น setState จาก parent ใช้ส่งค่าที่ผู้ใช้กรอกกลับไปยัง parent components เพื่อนำไปใช้งานต่อไป |
encrypt | - | ยังไม่ได้พัฒนา |
algorithm | - | ยังไม่ได้พัฒนา |
import React, { useState } from "react";import Pin, { ShowPin } from "./Pin";
// import styles from "./App.module.css";
function App() { const [value, setValue] = useState(); const handleChangeValue = (val) => { setValue({ value: val }); };
return ( <React.Fragment> <div style={{ width: "100%", marginTop: "50px", textAlign: "center", }} > <Pin keypad="dot" onChangeValue={handleChangeValue} /> <button style={{ width: "200px", height: "60px", borderRadius: "4px", border: "1px solid #00a1ff", color: "#00a1ff", }} onClick={() => { ShowPin(); }} > OPTEN, MY MODAL! </button> </div> </React.Fragment> );}
export default App;
import React, { useEffect, useState } from "react";import styles from "./Pin.module.css";
function Pin(props) { let initialSetting = { max: 6, keypad: "number", // number | dot random: false, // true | false onChangeValue: () => {}, }; const [setting, setSetting] = useState(initialSetting);
useEffect(() => { // props.max && setSetting({ ...setting, max: props.max }); // props.keypad && setSetting({ ...setting, keypad: props.keypad }); // props.random && setSetting({ ...setting, random: props.random }); // props.onChangeValue && setSetting({ ...setting, onChangeValue: props.onChangeValue });
let data = { max: props.max ? props.max : setting.max, keypad: props.keypad ? props.keypad : setting.keypad, random: props.random ? props.random : setting.random, onChangeValue: props.onChangeValue ? props.onChangeValue : setting.onChangeValue, } setSetting(data);
// setSetting({ ...props }); }, [props]);
const [setup, setSetup] = useState({ arr: [1, 2, 3, 4, 5, 6, 7, 8, 9], // algorithm: "md5", }); useEffect(() => { if (setting.random) { setSetup({ arr: shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]) }); } }, []);
const [input, setInput] = useState([]);
return ( <React.Fragment> <div id="modal-pin" className={styles.wrapper__size} style={{ display: "none" }} > <div className={styles.pin_blur}></div> <div className={styles.pin}> {/* <div className={styles.pin__header}></div> */} <div className={styles.pin__body}> <div className={styles.pin__body__message}> <div className={styles.pin__body__message__title}> <span>Enter PIN for trezor</span> </div> <div className={styles.pin__body__message__description}> <span>The PIN layout is displayed on your Trezor.</span> </div> </div> <div className={styles.pin__body__input}> <div className={styles.pin__body__input__box}> <div className={styles.pin__body__input__box__flex}> <input type="password" autoComplete="off" readOnly={true} value={input .toString() .replaceAll(",", "") .split("") .reverse() .join("")} /> <span className={styles.noselect} onClick={() => { if (input.length > 0) { setInput(input.slice(1)); } }} ></span> </div> </div> </div> <div className={styles.pin__body__button}> <div className={styles.pin__body__button__flex}> {setup.arr.map((item) => { return ( <div key={item} className={`${styles.pin__body__button__flex__item} ${styles.noselect} ${ setting.keypad === "dot" && styles.dot }`} onClick={() => { if (input.length > 0) { if (input.length < setting.max) { let data = []; data.push(item); data = data.concat(input); setInput(data); } } else { let data = []; data.push(item); setInput(data); } }} > {setting.keypad === "number" ? item : null} </div> ); })} </div> </div> <div className={styles.pin__body__submit}> <button onClick={() => { if (input.length > 0) { setting.onChangeValue( input .toString() .replaceAll(",", "") .split("") .reverse() .join("") ); }
setInput([]); window.document.getElementById("modal-pin").style.display = "none"; }} > Confirm </button> </div> <div className={styles.pin__body__help}> <span> Not sure how PIN work?{" "} <a href="#"> <u>Learn more</u> </a> </span> </div> </div> {/* <div className={styles.pin__footer}></div> */} </div> </div> </React.Fragment> );}
function shuffle(array) { var i = array.length, j = 0, temp;
while (i--) { j = Math.floor(Math.random() * (i + 1));
// swap randomly chosen element with current element temp = array[i]; array[i] = array[j]; array[j] = temp; }
return array;}
export default Pin;
function ShowPin() { window.document.getElementById("modal-pin").style.display = "block";}
export { ShowPin };
* { margin: 0; padding: 0; box-sizing: border-box;}.noselect { -webkit-touch-callout: none; /* iOS Safari */ -webkit-user-select: none; /* Safari */ -khtml-user-select: none; /* Konqueror HTML */ -moz-user-select: none; /* Old versions of Firefox */ -ms-user-select: none; /* Internet Explorer/Edge */ user-select: none; /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */}.wrapper__size { min-height: 100vh; display: block; position: absolute; left: 0; right: 0; top: 0;}.pin { position: absolute; margin-left: auto; margin-right: auto; left: 0; right: 0; text-align: center; width: 100%; max-width: 500px; margin-top: 50px; z-index: 9999; background-color: rgba(255, 255, 255, 1); box-shadow: rgb(0 0 0 / 8%) 0px 6px 10px;}.pin_blur { filter: blur(8px); -webkit-filter: blur(8px); /* background-image: url(https://source.unsplash.com/random); */ background-color: rgba(200, 200, 200, 1); width: 100%; height: 100vh; position: absolute;}.pin__header {}.pin__body { display: flex; flex-direction: column;
max-width: 380px; margin: 0px auto;}.pin__body__message { padding: 20px; text-align: center;}.pin__body__message__title { padding: 10px;}.pin__body__message__title span { font-size: 1.5em;}.pin__body__message__description { padding: 10px;}.pin__body__message__description span { font-size: 1em;}.pin__body__input { padding: 0px 20px; text-align: center;}.pin__body__input__box { border: 2px solid rgba(145, 145, 145, 0.5);}.pin__body__input__box__flex { display: flex;}.pin__body__input__box__flex input { text-align: right; font-size: 3.1em; width: 100%; max-height: 60px;
border: none; color: rgba(0, 0, 0, 0.8);}.pin__body__input__box__flex input:read-only:focus { outline: none;}.pin__body__input__box__flex span { color: rgba(0, 0, 0, 1); width: 100%; max-width: 60px; cursor: pointer;}.pin__body__input__box__flex span::after { content: "\2715"; font-size: 24px; display: flex; justify-content: center; align-items: center; height: 100%;}
.pin__body__button { padding: 10px 20px 20px 20px; text-align: center;}.pin__body__button__flex { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px;}.pin__body__button__flex__item { padding: 20px; border: 2px solid rgba(145, 145, 145, 0.5); border-radius: 2px; width: 100px; height: 100px; cursor: pointer;
font-size: 24px; display: flex; justify-content: center; align-items: center; /* height: 100%; */}.pin__body__button__flex__item.dot::before { content: "\A"; width: 10px; height: 10px; border-radius: 50%; background: rgba(0, 0, 0, 0.6); position: absolute;}.pin__body__submit { padding: 20px; text-align: center;}.pin__body__submit button { width: 100%; padding: 16px; border: none; border-radius: 2px; background: rgba(90, 208, 146, 1);
font-size: 1.2em; color: rgba(255, 255, 255, 1); cursor: pointer;}.pin__body__help { padding: 20px; text-align: center;}.pin__body__help span {}.pin__body__help span a { font-size: 1.2em; color: rgba(90, 208, 146, 1);}.pin__footer {}
สุดท้าย ก็หวังว่าบทความนี้จะเป็นประโยชน์กับใครหลาย ๆ คนนะครับ