const { useState, createContext, useContext, useEffect } = React;
// データのコンテキストを作成
const DataContext = createContext();
//パスワードをhasu化するためのcrypto API
async function hashPassword(password) {
const encoder = new TextEncoder();
const data = encoder.encode(password);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
return hashHex;
}
//データを管理するDataprovider-------------------------------------------
function DataProvider({ children }) {
const [LOGIN, setLOGIN] = useState('');
const [NAME, setNAME] = useState('');
const [BIRTHDAY, setBIRTHDAY] = useState('');
const [EMAIL, setEMAIL] = useState('');
const [PASSWORDHASH, setPASSWORDHASH] = useState('');
const [errors, setErrors] = useState({
EMAIL: false,
BIRTHDAY: false,
SEI: false,
MEI: false,
POPUPNEWPASSWORD: false,
POPUPCOMFIRMPASSWORD: false
});
const [errorMessages, setErrorMessages] = useState({
EMAIL: '',
BIRTHDAY: '',
SEI: '',
MEI: '',
POPUPNEWPASSWORD: '',
POPUPCOMFIRMPASSWORD: ''
});
//ポップアップ専用
//パスワード再設定によりユーザー検証
const [isPWRecreatePopup, setIsPWRecreatePopup] = useState(false);
//パスワード再設定ポップアップ
const [isPasswordResetPopup, setIsPasswordResetPopup] = useState(false);
return (
// 選択された値と、それをセットする関数をコンテキストとして提供
{children}
);
}
//-------------------------------------------------------------------------------------
//全体を表すコンポーネント
function Member_Login() {
return (
);
}
//全体を表すコンポーネント
function LoginContent() {
const { setLOGIN } = useContext(DataContext);
useEffect(() => {
const fetchUserData = async () => {
const userId = sessionStorage.getItem('USER_ID');
if (userId) {
try {
const response = await fetch(`/Regist/getUserById?USER_ID=${userId}`);
const data = await response.json();
if (data && data.length > 0) {
console.log("data:", data[0]);
setLOGIN(data[0].name);
} else {
alert('会員情報の取得に失敗しました。');
}
} catch (error) {
console.error('会員情報取得エラー:', error);
alert('会員情報の取得中にエラーが発生しました。');
}
}
};
fetchUserData();
}, [setLOGIN]);
return (
);
}
// Member_RegistコンポーネントをDOMにレンダリング
const memberElement = document.getElementById('member_Login');
const memberRoot = ReactDOM.createRoot(memberElement);
memberRoot.render();
//-----------------------------------------------------------------------------------------------------
//headerのコンポーネント
function TOP_HEADER() {
return (
);
}
//logoのコンポーネント
function LOGO() {
return (
);
}
//タブのコンポーネント
function TOP_TAB() {
const { LOGIN } = useContext(DataContext);
const handleLoginClick = (event) => {
event.preventDefault();
// dorpdownを表示する
const dropdown = document.getElementById("login_dropdown");
if (dropdown) {
dropdown.style.display = dropdown.style.display === "block" ? "none" : "block";
}
};
const MenuBarOnClick = (event) => {
event.preventDefault();
// dorpdownを表示する
const menuBar = document.getElementById("top_tab");
if (menuBar) {
menuBar.style.display =
menuBar.style.display === "block" ? "none" : "block";
}
};
return (
);
}
//-----------------------------------------------------------------------------------------------------
//ログインフォームのコンポーネント
function LOGIN_CONTAINER() {
return (
);
}
function LOGIN_MAIN() {
return (
ログイン
);
}
//Login部分のコンポーネント
function LOGIN_INNER() {
return (
);
}
function LOGIN_WRAP() {
return (
);
}
function FORM_MEMBER_TITLE() {
return (
会員の方
);
}
function FORM_MEMBER_TEXT() {
return (
);
}
function LOGIN_INPUT_AREA() {
const { setEMAIL, setPASSWORDHASH } = useContext(DataContext);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const [emailErrorMessage, setEmailErrorMessage] = useState('');
const [passwordErrorMessage, setPasswordErrorMessage] = useState('');
const handleLogin = async (event) => {
event.preventDefault();
if (email == '') {
setEmailErrorMessage('メールアドレスを入力してください');
return;
} else if (!validateEmail(email)) {
setEmailErrorMessage('正しいメールアドレスの形式で入力をお願いします');
return;
}
setEMAIL(email);
if (password == '') {
setPasswordErrorMessage('パスワードを入力してください');
return;
}
try {
const hashedPassword = await hashPassword(password);
setPASSWORDHASH(hashedPassword);
const response = await fetch('/Regist/getUser', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `EMAIL=${encodeURIComponent(email)}&PASSWORDHASH=${encodeURIComponent(hashedPassword)}`,
});
const data = await response.json();
if (data && data.length > 0) {
console.log("data:", data[0]);
const userId = data[0].user_ID;
console.log("user_id:", userId);
if (userId !== undefined) {
sessionStorage.setItem('USER_ID', userId);
window.location.href = '/mypage_appointment';
} else {
setErrorMessage('このアカウントはまだ会員登録していません。');
}
} else {
setErrorMessage('メールアドレスまたはパスワードが正しくありません。もう一度ご確認の上、入力してください。');
}
} catch (error) {
console.error('ログインエラー:', error);
setErrorMessage('ログイン中にエラーが発生しました。');
}
};
const validateEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const handleEmailBlur = () => {
if (email == '') {
setEmailErrorMessage('メールアドレスを入力してください');
} else if (!validateEmail(email)) {
setEmailErrorMessage('正しいメールアドレスの形式で入力をお願いします');
} else {
setEmailErrorMessage('');
}
};
const handlePasswordBlur = () => {
if (password == '') {
setPasswordErrorMessage('パスワードを入力してください');
} else {
setPasswordErrorMessage('');
}
};
return (
setEmail(e.target.value)}
onBlur={handleEmailBlur} />
{emailErrorMessage && (
{emailErrorMessage}
)}
setPassword(e.target.value)}
onBlur={handlePasswordBlur} />
{passwordErrorMessage && (
{passwordErrorMessage}
)}
{/* ログインエラーメッセージ */}
{errorMessage && (
{errorMessage.split('。')[0]}。
{errorMessage.split('。')[1]}
)}
{/* ログインボタン */}
ログイン
);
}
function MEMBER_FOOTER_CONTAINER() {
const { NAME, EMAIL, BIRTHDAY, setLOGIN,
isPasswordResetPopup, setIsPasswordResetPopup,
isPWRecreatePopup, setIsPWRecreatePopup } = useContext(DataContext);
//PWrecreatePopupパスワード再設定のポップアップを呼び出す--------------------------------------------------
const handleOpenPWreCreatePopup = () => {
sessionStorage.removeItem('USER_ID');
setLOGIN('');
setIsPWRecreatePopup(true);
}
const handleConfirm = async () => {
try {
const response = await fetch('/Regist/getUserforPassword', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `EMAIL=${encodeURIComponent(EMAIL)}&BIRTHDAY=${encodeURIComponent(BIRTHDAY)}&NAME=${encodeURIComponent(NAME)}`,
});
const data = await response.json();
if (data && data.length > 0) {
console.log("data:", data[0]);
const userId = data[0].user_ID;
console.log("user_id:", userId);
if (userId !== undefined) {
sessionStorage.setItem('USER_ID', userId);
} else {
alert('このアカウントはまだ会員登録していません。');
}
} else {
alert('メールアドレス、生年月日または氏名が正しくありません!');
return;
}
} catch (error) {
console.error('アカウント確認エラー:', error);
setErrorMessage('アカウントを確認中にエラーが発生しました。');
}
setIsPWRecreatePopup(false);
await handleSubmit();
}
const handleCancel = () => {
setIsPWRecreatePopup(false);
}
const handleSubmit = async () => {
setIsPasswordResetPopup(true);
}
return (
{/* パスワードrecreate */}
{/*
*/}
{isPWRecreatePopup && (
)}
{isPasswordResetPopup && (
setIsPasswordResetPopup(false)} />
)}
);
}
//----------------------------------- ポップアップ ---------------------------------------------------
//パスワード再設定によりユーザー検証pop-upのコンポーネント
function PWrecreatePopup({ onConfirm, onCancel }) {
const { NAME, setNAME, EMAIL, setEMAIL, BIRTHDAY, setBIRTHDAY,
errors, setErrors, errorMessages, setErrorMessages } = useContext(DataContext);
// const [mail, setMail] = useState('');
// const [birth, setBirth] = useState('');
const [sei, setSei] = useState('');
const [mei, setMei] = useState('');
//NAMEはseiとmeiの結合
useEffect(() => {
const fullName = `${sei} ${mei}`;
setNAME(fullName);
}, [sei, mei, setNAME]);
//メールアドレスの正規化
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
//全角数字を半角数字に変換する
const convertToHalfWidth = (str) => {
return str.replace(/[0-9]/g, (s) => {
return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
}).replace(/-/g, '-');
};
// 入力された日付をYYYY-MM-DDの形式に標準化する
const standardizeDate = (date) => {
const parts = date.split('-');
if (parts.length === 3) {
const year = parts[0];
const month = parts[1].length === 1 ? '0' + parts[1] : parts[1];
const day = parts[2].length === 1 ? '0' + parts[2] : parts[2];
return `${year}-${month}-${day}`;
}
return date;
};
//数字を含めるかどうかを確認
const containsNumbers = (str) => /[0-90-9]/.test(str);
//mailのinputboxのリマインド
const handleBlurEMAIL = () => {
if (EMAIL === '') {
setErrors(prev => ({ ...prev, EMAIL: true }));
setErrorMessages(prev => ({ ...prev, EMAIL: '入力お願いします' }));
} else if (!emailPattern.test(EMAIL)) {
setErrors(prev => ({ ...prev, EMAIL: true }));
setErrorMessages(prev => ({ ...prev, EMAIL: '正しいメールアドレスの形式で入力をお願いします' }));
} else {
setErrors(prev => ({ ...prev, EMAIL: false }));
setErrorMessages(prev => ({ ...prev, EMAIL: '' }));
}
}
//birthdayのinputboxのリマインド
const handleBlurBIRTHDAY = () => {
//フォーカスアウトすると全角数字を半角数字に自動的に変換する
let halfWidthBIRTHDAY = convertToHalfWidth(BIRTHDAY);
if (halfWidthBIRTHDAY === '') {
setErrors(prev => ({ ...prev, BIRTHDAY: true }));
setErrorMessages(prev => ({ ...prev, BIRTHDAY: '入力お願いします' }));
} else if (!/^\d{4}-\d{1,2}-\d{1,2}$/.test(halfWidthBIRTHDAY)) {
setErrors(prev => ({ ...prev, BIRTHDAY: true }));
setErrorMessages(prev => ({ ...prev, BIRTHDAY: '生年月日は「YYYY-MM-DD」の形式で入力してください' }));
} else {
halfWidthBIRTHDAY = standardizeDate(halfWidthBIRTHDAY);
setErrors(prev => ({ ...prev, BIRTHDAY: false }));
setErrorMessages(prev => ({ ...prev, BIRTHDAY: '' }));
}
setBIRTHDAY(halfWidthBIRTHDAY);
};
//seiのinputboxのリマインド
const handleBlurSei = () => {
if (!sei) {
setErrors(prev => ({ ...prev, SEI: true }));
setErrorMessages(prev => ({ ...prev, SEI: '入力お願いします' }));
} else if (containsNumbers(sei)) {
setErrors(prev => ({ ...prev, SEI: true }));
setErrorMessages(prev => ({ ...prev, SEI: '数字を含めないでください' }));
} else {
setErrors(prev => ({ ...prev, SEI: false }));
setErrorMessages(prev => ({ ...prev, SEI: '' }));
}
};
//meiのinputboxのリマインド
const handleBlurMei = () => {
if (!mei) {
setErrors(prev => ({ ...prev, MEI: true }));
setErrorMessages(prev => ({ ...prev, MEI: '入力お願いします' }));
} else if (containsNumbers(mei)) {
setErrors(prev => ({ ...prev, MEI: true }));
setErrorMessages(prev => ({ ...prev, MEI: '数字を含めないでください' }));
} else {
setErrors(prev => ({ ...prev, MEI: false }));
setErrorMessages(prev => ({ ...prev, MEI: '' }));
}
};
//現在登録されているメールアドレスと一致するかどうかを確認
const handleConfirmClick = async () => {
if (EMAIL === '' && BIRTHDAY === '' && sei === '' && mei === '') {
alert('情報を入力してください!');
return;
} else if (EMAIL === '') {
alert('メールアドレスを入力してください!');
return;
} else if (BIRTHDAY === '') {
alert('生年月日を入力してください!');
return;
} else if (sei === '' || mei === '') {
alert('氏名を入力してください!')
return;
}
// 確認ダイアログを表示
const isConfirmed = window.confirm('パスワード再設定しますか?');
if (isConfirmed) {
onConfirm();
}
}
return (
登録しているメールアドレス、生年月日と氏名を入力してください。
パスワードは上記の入力情報に基づいて再設定できます。
メールアドレス
setEMAIL(e.target.value)}
onBlur={handleBlurEMAIL} />
{errors.EMAIL && (
{errorMessages.EMAIL}
)}
生年月日
setBIRTHDAY(e.target.value)}
onBlur={handleBlurBIRTHDAY} />
{errors.BIRTHDAY && (
{errorMessages.BIRTHDAY}
)}
氏名
setSei(e.target.value)}
onBlur={handleBlurSei} />
{errors.SEI && (
{errorMessages.SEI}
)}
setMei(e.target.value)}
onBlur={handleBlurMei} />
{errors.MEI && (
{errorMessages.MEI}
)}
);
}
//----------------------------------------------------------------------------------------------------
//パスワード再設定ポップアップ
function PasswordResetPopup({ onClose }) {
const { setPASSWORDHASH, errors, setErrors, errorMessages, setErrorMessages } = useContext(DataContext);
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const handleSave = async () => {
let hasError = false;
if (newPassword === '') {
setErrors(prev => ({ ...prev, POPUPNEWPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPNEWPASSWORD: '入力お願いします' }));
hasError = true;
} else if (newPassword.length < 8) {
setErrors(prev => ({ ...prev, POPUPNEWPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPNEWPASSWORD: '8文字以上で入力ください' }));
hasError = true;
} else if (!/[A-Z]/.test(newPassword) || !/[a-z]/.test(newPassword) || !/[0-9]/.test(newPassword) || !/[\W_]/.test(newPassword)) {
setErrors(prev => ({ ...prev, POPUPNEWPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPNEWPASSWORD: '大小英文字、数字、記号が混在するパスワードを入力してください' }));
hasError = true;
}
if (confirmPassword === '') {
setErrors(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: '入力お願いします' }));
hasError = true;
} else if (confirmPassword !== newPassword) {
setErrors(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: '入力されたパスワードが上記と一致しません' }));
hasError = true;
}
if (hasError) {
return;
}
try {
const hashedPassword = await hashPassword(confirmPassword);
setPASSWORDHASH(hashedPassword);
const response = await fetch('/Regist/UpdateUserPASSWORD', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `PASSWORDHASH=${encodeURIComponent(hashedPassword)}&USER_ID=${encodeURIComponent(sessionStorage.getItem('USER_ID'))}`,
});
const result = await response.json();
if (result) {
alert('パスワードの更新に成功しました。');
onClose();
// window.location.href = '/member_login_general';
} else {
alert('パスワードの更新に失敗しました。');
}
} catch (error) {
console.error('パスワードの更新エラー:', error);
alert('パスワードの更新中にエラーが発生しました。');
}
};
//newpasswordのinputboxのリマインド
const handleBlurNEWPASSWORD = () => {
if (newPassword === '') {
setErrors(prev => ({ ...prev, POPUPNEWPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPNEWPASSWORD: '入力お願いします' }));
//パスワードを8文字以下で入力した場合
} else if (newPassword.length < 8) {
setErrors(prev => ({ ...prev, POPUPNEWPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPNEWPASSWORD: '8文字以上で入力ください' }));
//パスワードは数字、大小英文字と記号が混在してない場合
} else if (!/[A-Z]/.test(newPassword) || //大英文字
!/[a-z]/.test(newPassword) || //小英文字
!/[0-9]/.test(newPassword) || //数字
!/[\W_]/.test(newPassword)) { //記号
setErrors(prev => ({ ...prev, POPUPNEWPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPNEWPASSWORD: '大小英文字、数字、記号が混在するパスワードを入力してください' }));
} else {
setErrors(prev => ({ ...prev, POPUPNEWPASSWORD: false }));
setErrorMessages(prev => ({ ...prev, POPUPNEWPASSWORD: '' }));
}
};
//comfirmedpasswordのinputboxのリマインド
const handleBlurCONFIRMPASSWORD = () => {
if (confirmPassword === '') {
setErrors(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: '入力お願いします' }));
} else if (confirmPassword !== newPassword) {
setErrors(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: true }));
setErrorMessages(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: '入力されたパスワードが上記と一致しません' }));
} else {
setErrors(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: false }));
setErrorMessages(prev => ({ ...prev, POPUPCOMFIRMPASSWORD: '' }));
}
};
return (
新しいパスワード ※8文字以上で設定してください
setNewPassword(e.target.value)}
onBlur={handleBlurNEWPASSWORD} />
{errors.POPUPNEWPASSWORD && (
{errorMessages.POPUPNEWPASSWORD}
)}
新しいパスワード(確認)※8文字以上で設定してください
setConfirmPassword(e.target.value)}
onBlur={handleBlurCONFIRMPASSWORD} />
{errors.POPUPCOMFIRMPASSWORD && (
{errorMessages.POPUPCOMFIRMPASSWORD}
)}
);
}
//-----------------------------------------------------------------------------------------------------
//会員登録ページ遷移部分のコンポーネント
function TO_REGIST_INNER() {
return (
);
}
//--------------------------------- フッター部分--------------------------------------------------
function LOFIN_FORM_FOOTER() {
return (
ヘルスマ © healthma Co.,Ltd. All Rights Reserved.
);
}