--- title: "クライアントの設定" url: https://docs.catalyst.zoho.com/ja/tutorials/birthday-greetings/nodejs/config-client/ description: "Job Schedulingサービスを使用して誕生日グリーティングアプリケーションを構築し、指定した相手にメールで自動的に誕生日の挨拶を送信します。" last_updated: 2026-08-28T07:59:38Z service: All Services type: tutorial related_links: - name: "クライアントディレクトリ" url: /ja/cli/v1/project-directory-structure/client-directory --- # クライアントの設定 クライアントコンポーネントを設定しましょう。 Reactウェブ[クライアントディレクトリ](https://docs.catalyst.zoho.com/ja/cli/v1/project-directory-structure/client-directory)には以下のファイルが含まれています: - クライアントのルートディレクトリには`client-package.json`ファイルが含まれており、クライアントコンポーネントの名前、バージョン、デフォルトのホームページ、およびリダイレクトページを定義する設定ファイルです。 - `birthdaygreetings`クライアントディレクトリには、Reactアプリのデフォルトプロジェクト構造に従い、2つのサブフォルダが含まれています: - `public`フォルダは一般的に、ウェブアプリのアイコンファイルや`index.html`ファイルなど、パブリックURLを通じてブラウザから公開アクセスできるファイルを格納するために使用されます。 - `src`フォルダには、Reactアプリをコンパイルする際にビルドフォルダに含まれるアプリケーションのソースファイルが含まれています。 - クライアントディレクトリには、[`package.json`](https://docs.npmjs.com/files/package.json)依存関係ファイルと隠し[`.gitignore`](https://docs.npmjs.com/files/package.json)ファイルも含まれています。 `BirthdayGreetings/birthdaygreetings/public`ディレクトリのファイルには以下が含まれます: - `Tests.js`、`index.js`、`reportWebVitals.js`、`logo.svg`、`App.test.js`などの[ネイティブReactファイル](https://reactjs.org/docs/getting-started.html#try-react)。 - `index.html` CatalystコンポーネントにアクセスするためのCatalyst Web SDKが含まれています。 - さらに、以下のファイルを作成します: - `embeddediframe.css`:アプリケーションのログインフォームに必要なスタイリング要素が含まれます。 - `fpwd.css`:アプリケーションのパスワード忘れ画面に必要なスタイリング要素が含まれます。 `BirthdayGreetings/birthdaygreetings/src`ディレクトリのファイルには以下が含まれます: - `setupTests.js`、`reportWebVitals.js`、`logo.svg`、`App.test.js`などのネイティブReactファイル。 - `App.js`:アプリケーションのハッシュルートが含まれます。 - `App.css`:アプリケーション全体のスタイリング要素が含まれます。 - `index.js`:アプリケーションのエントリーポイントとして機能します。 - `index.css`:`index.js`ファイルに存在する要素のスタイリングが含まれています。 - `src`ディレクトリに以下の追加ファイルを作成します: - `Layout.js`:アプリケーションのロジック用Reactコンポーネントが含まれます。 - `LoginPage.js`:Catalystコンソールで生成したログインページ用Reactコンポーネントが含まれます。 - `UserProfile.js`:トップバーとサーバーへのリマインダーデータ送信フォームを表示するユーザープロフィールページが含まれます。 - `UserProfile.css`:カスタムスクロールバーの設定やヘッダーセクションのレイアウト調整を含む、ユーザープロフィールページのスタイリング要素が含まれます。 - `Signup.js`:Catalystコンソールで生成したサインアップページ用Reactコンポーネントが含まれます。 - `Signup.css`:アプリケーションのサインアップページのスタイリング要素が含まれます。 - `ListUsers.js`:設定したすべてのリマインダーを一覧表示し、編集や削除を可能にし、Axiosリクエストを使用してリマインダーのステータスを切り替える機能を提供するページが含まれます。 - さらに、`src`ディレクトリに`components`というフォルダを作成する必要があります。`BirthdayGreetings/birthdaygreetings/src/components/`には以下のコードファイルが含まれます: - `form.jsx`:フォームデータの管理、入力変更の処理、`onSubmit`関数を通じて親コンポーネントへのフォームデータ送信を担当するフォームコンポーネントが含まれます。 - `modal.jsx`:名前、メッセージ、誕生日、メールの入力フィールドと更新ボタンを含む、ユーザーデータ編集用のモーダル機能が含まれます。 - `modal.css`:バックドロップと中央揃えのコンテンツを持つ、ユーザーデータ編集用のモーダルコンポーネントのレイアウト、入力フィールド、ボタンのスタイリングが含まれます。 - `ToggleSwitch.jsx`:機能の有効化や無効化など、2つの状態を切り替えるトグルスイッチコンポーネントのロジックが含まれます。 - `toggleSwitch.css`:チェック状態と未チェック状態のトランジション効果を持つスライドトグルスイッチのスタイリングが含まれます。 - `TopBar.jsx`:「`Add User`」や「`List User`」などのページへのリンク、中央のタイトル、右側の「`Sign-out`」ボタンを含むトップナビゲーションバーの構造が含まれます。 - `topBar.css`:レイアウト、ボタンの外観、スティッキーポジショニングを含む、トップナビゲーションバーのスタイリング要素が含まれます。 - `UserList.jsx`:各リマインダーのトグル、編集、削除オプションを含むリマインダーリストのレンダリング構造が含まれます。 - `Userlist.css`:レイアウト、アイテムのスタイリングを含む、ユーザーリストのスタイリング要素が含まれます。また、編集ボタンと削除ボタンのデザインも含まれます。 `index.html`、`embeddediframe.css`、`fpwd.css`、`App.js`、`App.css`、`index.css`、`index.js`、`Layout.js`、`LoginPage.js`、`UserProfile.css`、`UserProfile.js`、`Signup.js`、`Signup.css`、`form.jsx`、`Form.css`、`modal.jsx`、`modal.css`、`ToggleSwitch.jsx`、`toggleSwitch.css`、`TopBar.jsx`、`topBar.css`、`UserList.jsx`、および`Userlist.css`ファイルのコーディングを行います。 また、アプリケーションのホームページがログインページになるように`client-package.json`を変更します。 ### 追加のReactパッケージのインストール ファイルにコードを追加する前に、以下のパッケージをインストールする必要があります: * `react-router-dom`:このパッケージはハッシュルーティングを実行するために必要です。 * `axios`:クライアントのPromiseをスムーズに処理するためのパッケージです。 ターミナルで`BirthdayGreetings/birthdaygreetings/public/`ディレクトリから以下のコマンドを実行して、`react-router-dom`パッケージをインストールします: ```sh npm install react-router-dom ``` ![catalyst_tutorials_jobscheduling_client_router_dom](https://catalyst-docs-development.zohostratus.in/images/tutorials/birthday-greetings/catalyst_tutorials_jobscheduling_client_router_dom.webp) ターミナルで`BirthdayGreetings/birthdaygreetings/public/`ディレクトリから以下のコマンドを実行して、`axios`パッケージをインストールします: ```sh npm install axios ``` ![catalyst_tutorials_jobscheduling_client_axios](https://catalyst-docs-development.zohostratus.in/images/tutorials/birthday-greetings/catalyst_tutorials_jobscheduling_client_axios.webp) 必要なファイルを作成し、不要なファイルを削除した後のプロジェクトディレクトリです。 ![catalyst_tutorials_jobscheduling_final_proj_dir](https://catalyst-docs-development.zohostratus.in/images/tutorials/birthday-greetings/catalyst_tutorials_jobscheduling_final_proj_dir.webp) 以下のコードをコピーして、IDEを使用してクライアントディレクトリ(`birthdaygreetings/public/`)にある対応するファイルに貼り付け、ファイルを保存してください。 **index.html** ```xml <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <script src="https://static.zohocdn.com/catalyst/sdk/js/4.6.2/catalystWebSDK.js"> </script> <script src="/__catalyst/sdk/init.js"> </script> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"> </div> </body> </html> ``` **embeddediframe.css** ```css @font-face { font-family: "Roboto Mono"; font-weight: 400; font-style: normal; src: url("https://webfonts.zohowebstatic.com/robotomonoregular/font.eot"); src: url("https://webfonts.zohowebstatic.com/robotomonoregular/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.svg#RobotoMono-Regular") format("svg"); } @font-face { font-family: "LatoLgt"; font-weight: 300; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latolight/font.eot"); src: url("https://webfonts.zohowebstatic.com/latolight/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latolight/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latolight/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latolight/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latolight/font.svg#Lato-Light") format("svg"); } @font-face { font-family: "LatoReg"; font-weight: 400; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latoregular/font.eot"); src: url("https://webfonts.zohowebstatic.com/latoregular/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latoregular/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latoregular/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latoregular/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latoregular/font.svg#Lato-Regular") format("svg"); } @font-face { font-family: "LatoSB"; font-weight: 700; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latobold/font.eot"); src: url("https://webfonts.zohowebstatic.com/latobold/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latobold/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latobold/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latobold/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latobold/font.svg#Lato-Bold") format("svg"); } @font-face { font-family: "LatoB"; font-weight: 900; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latoblack/font.eot"); src: url("https://webfonts.zohowebstatic.com/latoblack/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latoblack/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latoblack/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latoblack/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latoblack/font.svg#Lato-Black") format("svg"); } @font-face { font-family: "signinicon"; src: url(/images/signinicon.eot); src: url(/images/signinicon.eot) format("embedded-opentype"), url(/__catalyst/auth/static-file?file_name=signinicon.woff2) format("woff2"), url(/__catalyst/auth/static-file?file_name=signinicon.ttf) format("truetype"), url(/__catalyst/auth/static-file?file_name=signinicon.woff) format("woff"), url("../images/fonts/signinicon.651f82b8f8f51f33cd0b6331f95b5b4f.svg") format("svg"); font-weight: normal; font-style: normal; font-display: block; } [class^="icon-"], [class*=" icon-"] { /* use !important to prevent issues with browser extensions that change fonts */ font-family: "signinicon" !important; speak: never; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; line-height: 1; /* Better Font Rendering =========== */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-hide:before { content: "\e907"; } .icon-show:before { content: "\e914"; } .icon-backarrow:before { content: "\e900"; } .icon-backup:before { content: "\e901"; } .icon-support:before { content: "\e915"; } body { font-family: "Roboto", sans-serif; margin: 0px; } .bg_one { display: block; position: fixed; top: 0px; left: 0px; height: 100%; width: 100%; background: url("../images/bg.49756b7c711696d95133fa95451f8e13.svg") transparent; background-size: auto 100%; z-index: -1; } .signin_container { height: 25rem; display: block; width: 520px; background-color: #fff; box-shadow: 0px 2px 30px #ccc6; margin: auto; position: relative; z-index: 1; margin-top: auto; overflow: hidden; } .mod_container { width: 500px; } .checkbox_label { display: inline-block; font-size: 14px; margin: 0px 6px; float: left; cursor: pointer; line-height: 20px; } .signin_box { min-height: 520px; height: auto; background: #fff; box-sizing: border-box; border-radius: 2px; transition: all 0.1s ease-in-out; float: left; overflow-y: auto; display: table-cell; border-right: 2px solid #f1f1f1; width: 100%; padding: 0px 30px; height: auto; border-right: none; } .nopassword_message { display: table-cell; font-size: 14px; color: #222222; letter-spacing: 0px; line-height: 20px; height: auto; width: auto; margin-left: 10px; font-weight: 400; padding-left: 10px; } .portal_logo { display: block; height: 30px; width: auto; margin-bottom: 20px; background-size: auto 100%; } .pointer { cursor: pointer; } #forgotpassword { cursor: default; } #forgotpassword > a { cursor: pointer; } .text16 { display: block; text-align: center; margin-bottom: 30px; color: #626262; font-size: 16px; font-weight: 500; text-decoration: none; } .checkbox { float: left; z-index: 0; height: 12px; width: 12px; display: inline-block; border: 2px solid #ccc; border-radius: 2px; position: relative; top: 1.5px; overflow: hidden; background-color: #fff; } .show_hide_password { font-size: 34px; color: #a7a7a7; position: relative; top: -39px; right: 13px; float: right; cursor: pointer; height: 20px; } .pass_policy, .pass_policy_error { color: #8c8c8c; font-size: 14px; padding-top: 10px; } .pass_policy_error { color: #ed7500; display: block; } .checkbox_check { position: absolute; z-index: 1; opacity: 0; left: 50px; margin: 0px; height: 16px; cursor: pointer; width: 16px; } .checkbox_div { display: none; height: 16px; width: auto; margin-bottom: 30px; } .checkbox_div { display: block; } #terminate_session_form .checkbox_mod { margin-top: 50px; } .checkbox_tick { display: block; height: 3px; width: 8px; border-bottom: 2px solid #fff; border-left: 2px solid #fff; transform: rotate(-45deg); margin: 2px 1px; } .passexpsuccess { display: none; height: 106px; width: 178px; background: url("../images/passexpiry.db4c66debd4dd8880655f338ead6b973.png") no-repeat transparent; background-size: auto 100%; margin: 0px auto; margin-bottom: 20px; } .signin_head { display: block; font-size: 24px; font-weight: 500; margin-bottom: 30px; line-height: 30px; transition: all 0.1s ease-in-out; } .rightside_box { width: 390px; height: auto; float: right; box-sizing: border-box; padding: 40px; background-color: #fff; display: table-cell; } .service_name, .backup_desc, .pass_name { display: block; font-size: 16px; color: #000; font-weight: 400; } .titlename { display: block; font-size: 24px; color: #000; font-weight: 400; text-transform: capitalize; width: auto; margin-bottom: 20px; } .extramargin { margin-top: 10px; } .show_hide_password { font-size: 34px; color: #a7a7a7; position: relative; top: -39px; right: 13px; float: right; cursor: pointer; height: 20px; } .textbox_div { display: block; margin-bottom: 30px; position: relative; } .textbox_label { display: block; font-size: 14px; color: #626262; padding-bottom: 10px; } .textbox { display: block; width: 100%; height: 44px; box-sizing: border-box; border-radius: 2px; text-indent: 12px; font-size: 16px; outline: none; border: none; padding-right: 12px; transition: all 0.2s ease-in-out; background: #f1f1f1; border: 1px solid #e4e4e4; } .textbox:valid { border: 2px solid #f4f6f8; } .textindent42 { text-indent: 36px; } .textindent62 { text-indent: 56px; } .textintent52 { text-indent: 46px; } ::-webkit-credentials-auto-fill-button { visibility: hidden; pointer-events: none; position: absolute; right: 0px; } input[type="text"], input[type="password"], input[type="email"], input[type="number"] { -webkit-appearance: none; -moz-appearance: none; appearance: none; } .errorborder:focus, .textbox.errorborder { border-bottom: 2px solid #ff8484; } .btn { cursor: pointer; display: block; width: 100%; height: 44px; border-radius: 4px; letter-spacing: 0.5; font-size: 14px; font-weight: 600; outline: none; border: none; margin: auto; text-transform: uppercase; margin-bottom: 30px; transition: all 0.2s ease-in-out; } .signupbtn { width: 250px; margin-left: 0px; } .blue { box-shadow: 0px 2px 2px #fff; background-color: #159aff; color: #fff; } .grey { background-color: #f3f3f3; color: #3a3a3a; letter-spacing: 0px; } .green { box-shadow: 0px 2px 2px #fff; background-color: #00c573; color: #fff; } .blue:hover { background-color: #0966c2; cursor: pointer; box-shadow: 0px 2px 2px rgba(90, 183, 254, 0.2); } .changeloadbtn { display: block; height: 44px; width: 44px; border-radius: 22px; padding: 0px; } .changeloadbtn:before { content: ""; height: 20px; width: 20px; display: inline-block; margin: 9px; border: 3px solid #fff; border-top: 3px solid #5ab7fe; border-radius: 50%; animation: spin 0.5s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .hellouser { margin-bottom: 30px; } .username { display: inline-block; max-width: 100%; font-size: 16px; font-weight: 500; line-height: 24px; overflow: hidden; text-overflow: ellipsis; padding-right: 10px; float: left; } .Notyou { display: inline-block; font-size: 16px; line-height: 24px; } .signup_text { text-align: center; margin: 20px 0px; font-size: 16px; } .backbtn { display: none; float: left; height: 28px; width: 28px; border-radius: 50%; position: absolute; padding: 0px 5px; cursor: pointer; overflow: hidden; transition: all 0.1s ease; } .zeroheight { width: 0px; height: 0px; overflow: hidden; display: block; } #captcha, #bcaptcha { background: #fff; width: 60%; display: inline-block; } #captcha_img, #bcaptcha_img { width: 40%; float: right; background-color: #ffffff; border-left: none; } #captcha_img img, #bcaptcha_img img { height: 40px; } .reloadcaptcha { float: right; clear: both; margin-top: -37px; height: 30px; width: 30px; border-radius: 50px; background: url("../images/reload.eaef7ea18b680bc07558164c918909a6.png") no-repeat transparent 5px; background-size: 50%; display: inline-block; cursor: pointer; } #captcha_container { display: none; } .options { display: block; width: 100%; max-width: 500px; min-height: 80px; padding: 0px 50px; cursor: pointer; } .options:hover { background-color: #f9f9f9; } .option_details { display: inline-block; height: auto; width: 320px; margin-left: 15px; } .option_title { display: block; font-size: 16px; font-weight: 500; } .img_option { display: table-cell; height: 24px; width: 24px; color: #499aff; font-size: 24px; vertical-align: top; } .errorlabel { color: #e92b2b; } .fielderror { display: none; font-size: 14px; margin-top: 10px; } .fielderror a { text-decoration: none; color: #309ff4; } .bluetext { color: #309ff4; cursor: pointer; } #country_code_select { width: 50px; height: 40px; position: absolute; opacity: 0; display: none; z-index: 0; } .select_country_code { width: 50px; height: 40px; display: inline-block; float: left; position: absolute; line-height: 40px; text-align: center; font-size: 16px; color: black; display: none; z-index: 0; } .pic { width: 20px; height: 14px; background-size: 280px 252px; background-image: url("../images/Flags2x.0b8394efb0ea9167cef2465fb8f63d78.png"); float: left; } .cc { float: right; color: #aeaeae; } .cn { margin-left: 10px; } .select2-results__option--highlighted { background: #f4f6f8; } .searchparent { height: auto; } .searchlbl { font-size: 10px; font-weight: bolder; display: inline-block; margin-top: 15px; margin-bottom: 10px; margin-left: 10px; } .cntrysearch { width: 380px; height: 32px; border-radius: 2px; font-size: 14px; box-sizing: border-box; padding: 8px 10px; background: #f7f7f7; outline: none; border: none; margin-top: 10px; } .select2-results__option { list-style-type: none; height: 40px; box-sizing: border-box; padding: 12px 20px; font-size: 14px; line-height: 16px; } .select2-search__field { width: 380px; height: 32px; border: none; outline: none; background: #f7f7f7; border-radius: 2px; margin: 10px 0 0 10px; font-size: 14px; padding: 10.5px 8px; } .select2-selection { display: inline-block; outline: none; /* background-color: #F4F6F8; */ height: 40px; text-align: center; padding: 10px; box-sizing: border-box; cursor: pointer; } .selection { transition: all 0.2s ease-in-out; -webkit-user-select: none; display: inline-block; white-space: nowrap; overflow: hidden; width: 0px; height: 43px; } #select2-combobox-results { padding-left: 0px; max-height: 200px; overflow-y: scroll; overflow-x: hidden; width: 400px; margin-top: 10px; margin-bottom: 0px; background: white; } .select2-container--open { z-index: 10; background: #ffffff; box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.13); width: auto; box-sizing: border-box; } .select2 { position: absolute; background: transparent; box-shadow: none; display: none; margin: 2px; } .select2-results__options { overflow-y: auto; max-height: 200px; } .selection { width: auto; width: -moz-fit-content; width: -webkit-fit-content; margin: auto; display: block; } .select2-search–-hide, .select2-selection__clear { display: none; } #otp_container, #enableotpoption, #mfa_ga_container, #mfa_otp_container, #mfa_totp_container, #recoverybtn, #recovery_container, #enableforgot, #enablesaml, .trustbrowser_ui, #backup_ver_container, #backup_container, #enablemore, .password_expiry_container, .terminate_session_container { display: none; } .errorlabel { color: #e92b2b; } .fielderror { display: none; font-size: 14px; margin-top: 10px; } .field_error { color: #f37272; font-size: 14px; padding-top: 10px; } #recoverybtn, #problemsignin, .tryanother { position: absolute; left: 0px; right: 0px; bottom: 40px; } .textbox_actions, .textbox_actions_saml, .textbox_actions_more { display: block; margin-top: 20px; height: 20px; } .bluetext_action { display: inline-block; float: left; font-size: 14px; color: #159aff; font-weight: 500; line-height: 16px; cursor: pointer; } .bluetext_action a { text-decoration: none; } .bluetext_action_right { float: right; } .textbox_actions { display: block; margin-top: 20px; height: 20px; } .Alert, .Errormsg { display: block; margin: auto; height: auto; min-width: 200px; width: fit-content; width: -moz-fit-content; max-width: 600px; background-color: #032239; border-radius: 6px; position: fixed; top: -100px; left: 0px; right: 0px; transition: all 0.2s ease; padding: 0px 20px; z-index: 2; } .tick_icon, .error_icon { display: inline-block; height: 20px; width: 20px; background-color: #22c856; border-radius: 50%; background-size: 60px; margin: 15px; float: left; } .tick_icon:after { display: block; content: ""; height: 5px; width: 9px; border-bottom: 2px solid #fff; border-left: 2px solid #fff; transform: rotate(-45deg); margin: 7px 6px; box-sizing: border-box; } .alert_message, .error_message { display: inline-block; font-size: 14px; color: #fff; line-height: 18px; margin: 16px 0px; margin-right: 20px; max-width: 510px; } .error_icon { background-color: #ff676f; } .error_icon:before, .error_icon:after { position: absolute; left: 44px; top: 20px; content: " "; height: 10px; width: 2px; background-color: #ffffff; } .error_icon:before { transform: rotate(45deg); } .error_icon:after { transform: rotate(-45deg); } .select2-results__options { padding-left: 0px; } .showcountry_code { width: 62px !important; } .textindent70 { text-indent: 70px; } .countrybox { width: 400px; height: 220px; overflow: auto; } .focusmanage { position: absolute; z-index: 10; width: 400px; height: 266px; box-sizing: border-box; padding: 10px; margin-top: -25px; background: #ffffff; box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.13); border-radius: 2px; } .recoveryhead { margin-bottom: 10px; } .nopassword_container { display: none; background: #ebf4fb; border: 1px solid #cbe8ff; border-radius: 5px; width: 400px; height: auto; position: absolute; bottom: 50px; box-sizing: border-box; padding: 20px; } .nopassword_icon { display: table-cell; margin: 0px; height: 30px; width: 30px; color: #0091ff; font-size: 30px; vertical-align: middle; } .mailsearch { width: 400px; height: 30px; padding: 0px 0px; border: none; position: absolute; } .bolder1 { font-weight: bolder; } #ui-id-1 { height: 200px; width: auto; outline: none; border: none; overflow-x: hidden; overflow-y: scroll; } .ui-menu-item-wrapper { overflow: auto; } .nonclickelem { color: #626262; pointer-events: none; } .trustdevicebox { width: 500px; min-height: auto !important; } .trustdevice { width: auto; float: left; margin-right: 18px; min-width: 100px; margin-bottom: 0px; } .loadwithbtn { display: inline-block; height: 22px; width: 22px; border: 3px solid #fff; border-radius: 50%; position: absolute; margin: -2px; box-sizing: border-box; border-left: 3px solid transparent; animation-name: rotate1; animation-iteration-count: infinite; animation-duration: 1s; animation-timing-function: linear; } @keyframes rotate1 { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .waitbtn .waittext, .loadbtntext { display: inline-block; text-indent: 25px; } #waitbtn { display: none; } .loadwithbtn:before { display: inline-block; content: ""; height: 22px; width: 22px; border: 3px solid #ffffff30; border-radius: 50%; margin: -3px -11px; position: absolute; box-sizing: border-box; } .notnowbtn .loadwithbtn { border: 3px solid #3a3a3a; border-left: 3px solid transparent; } .trustdevice .loadwithbtn { display: none; } #recoverybtn, #problemsignin, .tryanother { display: none; bottom: 50px; width: fit-content; margin: 0px auto; cursor: pointer; } #recoverOption, #verify_totp_container, #verify_qr_container { display: none; } .backoption { width: 30px; height: 30px; font-size: 24px; display: inline-block; float: left; color: #666666; padding: 3px; box-sizing: border-box; margin-right: 5px; border-radius: 15px; cursor: pointer; } .backoption:hover { background: #f4f4f4; } .rec_head_text, .backoption { display: table-cell; } .options, .optionstry { display: table; width: 100%; height: auto; padding: 20px 50px; box-sizing: border-box; cursor: pointer; } .options:hover, .optionstry:hover { background-color: #f9f9f9; } .option_details, .option_details_try { height: auto; width: auto; padding-left: 10px; vertical-align: top; box-sizing: border-box; } .option_title_try { display: block; font-size: 16px; font-weight: 500; } .option_description { display: block; font-size: 13px; line-height: 20px; color: #696969; margin-top: 5px; } .img_option_try { margin: 12px 0px; } .img_option { font-size: 30px; color: #499aff; } .option_details { display: table-cell; } .problemsignincon, .recoverymodes, .addaptivetfalist, #recoverymodeContainer { width: auto; margin: 0px -50px; } .line { background-color: #f1f1f1; width: 100%; height: 2px; border-radius: 1px; margin-bottom: 20px; } .terminate_session_container .signin_head { margin-bottom: 20px; } #terminate_session_form .checkbox_div { position: relative; margin-bottom: 10px; } #terminate_session_form .checkbox_mod { margin-top: 30px; } #terminate_session_form .checkbox_check { left: 15px; } #terminate_session_form .checkbox_check:checked ~ .checkbox { background-color: #159aff; border-color: #159aff; } #terminate_session_form .showOneAuthLable { border: 1px solid #e7e7e7; border-radius: 10px 10px 0px 0px; box-sizing: border-box; max-width: 420px; height: auto; overflow: auto; margin-bottom: 0px; } .oneAuthLable { display: inline-flex; max-width: 420px; padding: 15px; align-items: center; margin-bottom: 10px; box-sizing: border-box; border: 1px solid #e7e7e7; border-top: none; border-radius: 0px 0px 15px 15px; } .oneauth_icon { display: inline-block; width: 40px; height: 40px; border-radius: 14px; background-size: 40px 40px; } .one_auth_icon_v2 { background-image: url(../images/oneAuth2.4b2a6945d5ecd70b703ba18f5f11eb68.png); } .oneAuthLable .text_container { flex: 1; margin: 0px 10px; } .oneAuthLable .text_header { font-size: 12px; font-weight: 500; margin-bottom: 4px; } .oneAuthLable .text_desc { font-size: 10px; line-height: 14px; } .oneAuthLable .togglebtn_div { height: 16px; padding: 4px; width: 30px; display: inline-block; position: relative; } .oneAuthLable .real_togglebtn { cursor: pointer; display: inline-block; position: relative; height: 16px; width: 30px; z-index: 1; opacity: 0; position: absolute; margin: 0px; } .real_togglebtn:checked ~ .togglebase { background-color: #10bc83; } .real_togglebtn:checked ~ .togglebase .toggle_circle { left: 16px; } .oneAuthLable .togglebase { height: 16px; width: 30px; display: inline-block; background: #ccc; border-radius: 10px; position: absolute; } .oneAuthLable .toggle_circle { transition: all 0.2s ease-in-out; height: 12px; width: 12px; background-color: #fff; border-radius: 10px; display: inline-block; position: absolute; left: 2px; top: 2px; box-shadow: 0px 0px 5px #999; } @media only screen and (-webkit-min-device-pixel-ratio: 2), not all, not all, not all, only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .google_icon { background-color: #fff; box-shadow: 0px 0px 2px #00000012, 0px 2px 2px #00000024; } .google_icon .fed_icon { background: url("../images/signin_icons@2x.c0c72f3600a6f5ec03c9119d5a7d0518.png") no-repeat transparent; background-size: 205px auto; background-position: -10px -10px; } .MS_icon { background-color: #2f2f2f; } .MS_icon .fed_icon { background: url("../images/signin_icons@2x.c0c72f3600a6f5ec03c9119d5a7d0518.png") no-repeat transparent; background-size: 205px auto; background-position: -38px -10px; } .linkedin_fed_box { background-color: #0966c2; } .linkedin_fed_box .fed_icon { background: url("../images/signin_icons@2x.c0c72f3600a6f5ec03c9119d5a7d0518.png") no-repeat transparent; background-size: 205px auto; background-position: -67px -11px; } .large_box .linked_fed_icon { background-position: -9px -174px; } .fb_fed_box { background-color: #1877f2; } .fb_fed_box .fed_icon { background: url("../images/signin_icons@2x.c0c72f3600a6f5ec03c9119d5a7d0518.png") no-repeat transparent; background-size: 205px auto; background-position: -94px -10px; } .zoho_icon { background: url(../images/signin_icons@2x.c0c72f3600a6f5ec03c9119d5a7d0518.png) no-repeat transparent; background-size: 205px auto; background-position: -152px -174px; } } @media only screen and (max-width: 600px) { body { -webkit-tap-highlight-color: rgba(255, 255, 255, 0); } .nopassword_container { width: calc(100% - 60px); padding: 10px; box-sizing: border-box; } .signin_container { width: 100%; box-shadow: none; margin: 0 auto; position: relative; z-index: 1; margin-top: 40px; height: 27rem; overflow: hidden; } #captcha_img, #captcha, #bcaptcha_img, #bcaptcha { border: 2px solid #f4f6f8; border-radius: 2px; text-indent: 3px; width: 50%; outline: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; } .textbox, #verify_totp { background-color: transparent; border: none; border-bottom: 2px solid #f4f6f8; text-indent: 0px; border-radius: 0px; } .textbox:focus, #verify_totp { border: none; border-bottom: 2px solid #159aff; } .errorborder:focus, .textbox.errorborder { border-bottom: 2px solid #ff8484; } .backoption { margin-bottom: 10px; } .img_option { margin: 0px 10px 0px 0px !important; } .bg_one, .line { display: none; } .signin_head { margin-bottom: 30px; } .btn { margin-top: 10px; border-radius: 4px; } .changeloadbtn { border-radius: 22px; } .more { margin-right: 0px !important; } .textindent42 { text-indent: 36px; } .textindent62 { text-indent: 56px; } .textintent52 { text-indent: 46px; } .select2-selection { background-color: #f1f9ff; } .devices .select2-selection { background-color: #f1f9ff; } .select2-search__field { width: 280px; } .applynormal { width: 46% !important; min-width: 0px; } .borderless, .borderlesstry { line-height: 12px; font-size: 14px; } .alert_message, .error_message { max-width: 300px; width: 75%; } .Alert, .Errormsg { max-width: 400px !important; padding: 0px; min-width: 300px; } .error_icon:before, .error_icon:after { left: 24px; } ::placeholder { font-weight: 500; } .mobilehide { display: none !important; } #forgotpassword { margin-bottom: 0px; } #forgotpassword a { display: inline-block; } .fielderror { position: absolute; margin-top: 5px; } .trustdevicebox { width: auto; height: auto; } #recoverybtn, #problemsignin, .tryanother { position: initial !important; margin-top: 70px !important; } .problemsignincon, .recoverymodes, #recoverymodeContainer { width: 100%; margin-left: 0px; } } .hover-tool-tip { position: absolute; top: 15px; left: 335px; background: #fff; padding: 20px; box-shadow: 0px 0px 10px #0000001a; transition: opacity 0.1s; border-radius: 5px; z-index: 9; opacity: 0; } .hover-tool-tip::after { content: ""; position: absolute; width: 0; height: 0; margin-left: -8px; top: 25px; left: 0; box-sizing: border-box; border: 6px solid black; border-color: #ffffff transparent transparent #ffffff; transform-origin: 0 0; transform: rotate(-45deg); box-shadow: -6px -6px 10px 0 #0000001a; } .hover-tool-tip.no-arrow::after { content: none; } .hover-tool-tip ul { padding: 0; margin: 0px 0px 0px 15px; list-style: none; } .hover-tool-tip p { margin: 0px 0px 10px 0px; font-size: 14px; font-weight: 500; } .hover-tool-tip ul li { font-size: 12px; display: flex; align-items: center; white-space: nowrap; line-height: 25px; } .hover-tool-tip ul li.success::before { background-color: #0dbc83; } .hover-tool-tip ul li::before { content: ""; margin-right: 10px; background-color: red; width: 8px; height: 8px; border-radius: 50%; } .titlename, .service_name { display: none !important; } .signin_head { padding-top: 20px; } #login_id { text-indent: 0 !important; } .showcountry_code { display: none !important; } ``` **fpwd.css** ```css @font-face { font-family: "Roboto Mono"; font-weight: 400; font-style: normal; src: url("https://webfonts.zohowebstatic.com/robotomonoregular/font.eot"); src: url("https://webfonts.zohowebstatic.com/robotomonoregular/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/robotomonoregular/font.svg#RobotoMono-Regular") format("svg"); } @font-face { font-family: "LatoLgt"; font-weight: 300; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latolight/font.eot"); src: url("https://webfonts.zohowebstatic.com/latolight/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latolight/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latolight/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latolight/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latolight/font.svg#Lato-Light") format("svg"); } @font-face { font-family: "LatoReg"; font-weight: 400; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latoregular/font.eot"); src: url("https://webfonts.zohowebstatic.com/latoregular/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latoregular/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latoregular/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latoregular/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latoregular/font.svg#Lato-Regular") format("svg"); } @font-face { font-family: "LatoSB"; font-weight: 700; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latobold/font.eot"); src: url("https://webfonts.zohowebstatic.com/latobold/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latobold/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latobold/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latobold/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latobold/font.svg#Lato-Bold") format("svg"); } @font-face { font-family: "LatoB"; font-weight: 900; font-style: normal; src: url("https://webfonts.zohowebstatic.com/latoblack/font.eot"); src: url("https://webfonts.zohowebstatic.com/latoblack/font.eot?#iefix") format("eot"), url("https://webfonts.zohowebstatic.com/latoblack/font.woff2") format("woff2"), url("https://webfonts.zohowebstatic.com/latoblack/font.woff") format("woff"), url("https://webfonts.zohowebstatic.com/latoblack/font.ttf") format("truetype"), url("https://webfonts.zohowebstatic.com/latoblack/font.svg#Lato-Black") format("svg"); } @font-face { font-family: "Zoho_Puvi_Regular"; src: url("https://static.zohocdn.com/zohofonts/zohopuvi/4.0/Zoho_Puvi_Regular.eot"); src: url("https://static.zohocdn.com/zohofonts/zohopuvi/4.0/Zoho_Puvi_Regular.eot") format("embedded-opentype"), url("https://static.zohocdn.com/zohofonts/zohopuvi/4.0/Zoho_Puvi_Regular.woff2") format("woff2"), url("https://static.zohocdn.com/zohofonts/zohopuvi/4.0/Zoho_Puvi_Regular.otf") format("opentype"); font-weight: normal; font-style: normal; /* font-display: swap */ } @font-face { font-family: "signinicon"; src: url(/images/signinicon.eot); src: url(/images/signinicon.eot) format("embedded-opentype"), url(/images/signinicon.woff2) format("woff2"), url(/images/signinicon.ttf) format("truetype"), url(/images/signinicon.woff) format("woff"), url("../images/fonts/signinicon.651f82b8f8f51f33cd0b6331f95b5b4f.svg") format("svg"); font-weight: normal; font-style: normal; font-display: block; } [class^="icon-"], [class*=" icon-"] { /* use !important to prevent issues with browser extensions that change fonts */ font-family: "signinicon" !important; speak: never; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; line-height: 1; /* Better Font Rendering =========== */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-device:before { content: "\e90a"; } .icon-reload:before { content: "\e912"; } .icon-backarrow:before { content: "\e900"; } .icon-email:before { content: "\e904"; } .icon-hide:before { content: "\e907"; } .icon-otp:before { content: "\e90c"; } .icon-show:before { content: "\e914"; } body { margin: 0px; } ::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ color: #0003; } .bg_one { display: block; position: fixed; top: 0px; left: 0px; height: 100%; width: 100%; /* background: url("../images/bg.49756b7c711696d95133fa95451f8e13.svg") transparent; */ background-size: auto 100%; z-index: -1; } .titlename { display: block; font-size: 24px; color: #000; font-weight: 400; text-transform: capitalize; width: auto; margin-bottom: 20px; } .Alert, .Errormsg { display: flex; align-items: center; justify-content: center; margin: auto; height: auto; min-width: 200px; width: fit-content; width: -moz-fit-content; max-width: 600px; background-color: #032239; border-radius: 6px; position: fixed; top: -100px; left: 0px; right: 0px; transition: all 0.2s ease; padding: 0px 20px; z-index: 2; } .tick_icon, .error_icon { display: inline-block; height: 20px; width: 20px; background-color: #22c856; border-radius: 50%; background-size: 60px; margin: 0px 15px; float: left; position: relative; } .tick_icon:after { display: block; content: ""; height: 5px; width: 9px; border-bottom: 2px solid #fff; border-left: 2px solid #fff; transform: rotate(-45deg); margin: 7px 6px; box-sizing: border-box; } .alert_message, .error_message { display: inline-block; font-size: 14px; color: #fff; line-height: 18px; margin: 16px 0px; margin-right: 20px; max-width: 510px; } .error_icon { background-color: #ff676f; } .error_icon:before, .error_icon:after { position: absolute; left: 9px; top: 5px; content: " "; height: 10px; width: 2px; background-color: #ffffff; } .error_icon:before { transform: rotate(45deg); } .error_icon:after { transform: rotate(-45deg); } .loader { width: 36px; height: 36px; border: 4px solid #159aff; border-bottom: 4px solid transparent; border-radius: 50%; display: block; box-sizing: border-box; animation: rotate 1s linear infinite; position: absolute; top: 0px; z-index: 7; bottom: 0px; left: 0px; right: 0px; margin: auto; } @keyframes rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .blur { top: 0px; left: 0px; bottom: 0px; background: #fff; width: 100%; height: auto; margin: auto; position: absolute; z-index: 3; opacity: 0.9; display: block; } .bold_font { font-weight: 500; } .searchparent { height: auto; } .textbox_div { display: block; margin-bottom: 30px; position: relative; } .textbox { display: block; width: 100%; height: 44px; box-sizing: border-box; border-radius: 2px; text-indent: 12px; font-size: 16px; outline: none; border: none; padding-right: 12px; transition: all 0.2s ease-in-out; background: #f9f9f9; border: 1px solid #dddddd; } .textbox:hover, .textbox:valid, .textbox:focus { border: 1px solid #b9b9b9; } #last_password { padding-right: 40px; } ::-webkit-credentials-auto-fill-button { visibility: hidden; pointer-events: none; position: absolute; right: 0px; } input[type="text"], input[type="password"], input[type="email"], input[type="number"] { -webkit-appearance: none; -moz-appearance: none; appearance: none; } .errorborder { border: 2px solid #ff8484 !important; } .textbox:-webkit-autofill, .textbox:-webkit-autofill:hover, .textbox:-webkit-autofill:focus, .textbox:-webkit-autofill:active { -webkit-box-shadow: inset 0 0 0px 9999px #f9f9f9; -webkit-text-fill-color: black; background-color: #f9f9f9 !important; } .fielderror { display: none; font-size: 14px; margin-top: 10px; } .fielderror a { text-decoration: none; color: #309ff4; } #captcha_container { display: none; border: 1px solid #dddddd; width: 250px; padding: 10px; box-sizing: border-box; margin-top: 10px; border-radius: 4px; } #captcha { width: 100%; display: inline-block; height: 40px; padding: 0px 12px; text-indent: 0px; background: #f9f9f9; } #captcha_img { background-color: #ffffff; border: none; height: 60px; width: 150px; margin-left: 20px; } #captcha_img img { height: 50px; width: 150px; box-sizing: border-box; margin: 0px; } .reloadcaptcha { height: 30px; width: 30px; border-radius: 50%; display: inline-block; cursor: pointer; position: absolute; right: 20px; top: 20px; background-color: #f2f2f2; font-size: 30px; box-sizing: border-box; color: #0006; } .reloadcaptcha:hover { color: #000000b3; } .load_captcha_btn { animation: spin 0.5s linear infinite; } #Last_password_div .head_info { margin: 0px; } .zeroheight { width: 0px; height: 0px; overflow: hidden; display: block; } .btn { cursor: pointer; display: block; width: 100%; height: 44px; border-radius: 4px; letter-spacing: 0.5; font-size: 14px; font-weight: 600; outline: none; border: none; margin: auto; text-transform: uppercase; margin-bottom: 30px; transition: width 0.2s ease-in-out; } .blue { background-color: #159aff; color: #fff; } .grey { background-color: #f3f3f3; color: #3a3a3a; letter-spacing: 0px; } .green { box-shadow: 0px 2px 2px #fff; background-color: #00c573; color: #fff; } .blue:hover { background: #118be9; } .changeloadbtn { display: block; height: 44px; width: 44px; border-radius: 22px; padding: 0px; } .changeloadbtn:before { content: ""; height: 20px; width: 20px; display: inline-block; margin: 9px; border: 3px solid #fff; border-top: 3px solid #5ab7fe; border-radius: 50%; animation: spin 0.5s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .doneBtn { position: relative; } .doneBtn:before { content: ""; opacity: 1; height: 15px; width: 6px; border: unset; border-radius: unset; transform-origin: left top; border-right: 3px solid #fff; border-top: 3px solid #fff; left: 12px; top: 23px; margin: 0px; position: absolute; transform: scaleX(-1) rotate(135deg); animation: tickmark 0.8s ease; } @keyframes tickmark { 0% { height: 0px; width: 0px; border-radius: unset; opacity: 1; } 20% { height: 0px; width: 6px; opacity: 1; border-radius: unset; } 40% { height: 15px; width: 6px; opacity: 1; border-radius: unset; } 100% { height: 15px; width: 6px; opacity: 1; border-radius: unset; } } .doneWithContent span:before { content: ""; opacity: 1; height: 14px; width: 5px; border: unset; border-radius: unset; transform-origin: left top; border-right: 3px solid #fff; border-top: 3px solid #fff; display: inline-block; margin: 0px; position: relative; transform: scaleX(-1) rotate(135deg); top: 12px; left: -21px; } .doneWithContent { padding-left: 21px; position: relative; } .doneWithContent:after { position: absolute; height: 100%; content: ""; display: block; left: 0px; top: 0px; background: #00000008; animation-name: btn_loading; animation-duration: 4.3s; animation-iteration-count: 1; animation-timing-function: linear; } .restrict_icon { display: block; height: 102px; width: 100%; background: url(../images/URLError.76c2ce33de912ad7ae9d2fbfd93ec2c1.png) no-repeat transparent; background-size: auto 100%; margin: auto; margin-top: 30px; background-position: center; } .error_portion { display: none; } .error_content { text-align: center; } .error_content .error_header { font-size: 20px; font-weight: 500; margin-top: 30px; line-height: 26px; } .error_content .error_desc { font-size: 16px; margin: 10px 0px 30px 0px; line-height: 24px; font-weight: 500; color: #000000cc; } .retry_button { line-height: 44px; } .doneWithContent:hover { background: #159aff; } .doneWithContent span { width: 100%; display: block; transition: width 0.2s ease-in-out; white-space: nowrap; } @keyframes btn_loading { 0% { width: 0%; } 100% { width: 100%; } } .resend_label { display: block; text-align: center; } .push_resend { font-size: 14px; color: #626262; font-weight: 500; line-height: 16px; cursor: none; } .bottom_option { cursor: pointer; width: max-content; font-size: 16px; font-weight: 500; text-decoration: none; color: #0091ff; } .bottom_line_opt { width: 100%; display: flex; justify-content: center; position: absolute; left: 0px; bottom: 40px; } .errorlabel { color: #e92b2b; } .show_hide_password { font-size: 24px; color: #00000066; position: relative; top: -34px; right: 13px; float: right; cursor: pointer; line-height: 23px; } .show_hide_password:hover { color: #000000b3; } .select2-results__option { list-style-type: none; height: 40px; box-sizing: border-box; padding: 12px 20px; font-size: 14px; line-height: 16px; } .select2-search__field { width: 380px; height: 32px; border: none; outline: none; background: #f7f7f7; border-radius: 2px; margin: 10px 8px; font-size: 14px; padding: 10.5px 8px; } .select2-selection { display: inline-block; outline: none; background-color: #f9f9f9; height: 40px; text-align: center; padding: 10px; box-sizing: border-box; cursor: pointer; } .selection { transition: all 0.2s ease-in-out; -webkit-user-select: none; display: inline-block; white-space: nowrap; overflow: hidden; width: 0px; height: 43px; } #select2-combobox-results { padding-left: 0px; max-height: 200px; overflow-y: scroll; overflow-x: hidden; width: 400px; margin-top: 10px; margin-bottom: 0px; background: white; } .select2-container--open { z-index: 10; background: #ffffff; box-shadow: 0px 5px 8px 2px #0000000d; width: auto; box-sizing: border-box; } .select2 { position: absolute; background: transparent; box-shadow: none; display: none; margin: 2px; } .select2-results__options { overflow-y: auto; max-height: 200px; } .selection { width: auto; width: -moz-fit-content; width: -webkit-fit-content; margin: auto; display: block; } .select2-search--hide, .select2-selection__clear { display: none; } #country_code_select { width: 50px; height: 40px; position: absolute; opacity: 0; display: none; z-index: 0; } .select_country_code { width: 50px; height: 40px; display: inline-block; float: left; position: absolute; line-height: 39px; text-align: center; font-size: 16px; color: black; display: none; z-index: 0; } .pic { width: 20px; height: 14px; background-size: 280px 252px; background-image: url("../images/Flags2x.0b8394efb0ea9167cef2465fb8f63d78.png"); float: left; } .cc { float: right; color: #aeaeae; } .cn { margin-left: 10px; } .select2-results__option--highlighted { background: #f4f6f8; } .searchparent { height: auto; } .select2-results__options { padding-left: 0px; } .optionstry { display: table; width: 100%; height: auto; padding: 20px 50px; box-sizing: border-box; cursor: pointer; } .optionstry:hover { background-color: #f9f9f9; } .img_option_try { margin: 12px 0px; } .img_option { display: table-cell; width: 30px; color: #499aff; font-size: 30px; vertical-align: top; height: 30px; } .option_details_try { height: auto; width: auto; padding-left: 12px; vertical-align: top; box-sizing: border-box; } .option_title_try { display: block; font-size: 16px; font-weight: 500; } .option_description { display: block; font-size: 13px; line-height: 20px; color: #000c; margin-top: 5px; } #email_confirm_div .optionstry, #mobile_confirm_div .optionstry { padding: 22px 40px; } #email_confirm_div .img_option, #mobile_confirm_div .img_option { font-size: 20px; width: 20px; height: 20px; } #email_confirm_div .option_details_try, #mobile_confirm_div .option_details_try { line-height: 20px; } .otp_container::after, .mini_txtbox:after { content: attr(placeholder); height: 54px; line-height: 54px; position: absolute; color: #b9bcbe; left: 15px; top: 0px; z-index: 1; } .mini_txtbox:after { line-height: 42px; height: 42px; } .hidePlaceHolder::after { z-index: -1 !important; } .otp_verify { margin-top: 10px; } .toggle_active { background: #f9f9f9; border-radius: 2px; } .optionmod { margin-left: 0px; box-sizing: border-box; } .option_title_try { color: #000000; } .mini_btn { margin-left: 10px; width: 30%; float: right; font-size: 12px; margin-bottom: 0px; margin-right: 0px; } .backoption { width: 30px; height: 30px; font-size: 21px; display: inline-block; float: left; color: #666666; padding: 4px 0px; box-sizing: border-box; margin-right: 5px; border-radius: 15px; cursor: pointer; font-weight: 500; text-align: center; } .backoption:hover { background: #f4f4f4; } #select_reocvery_mobile .fieldcontainer, #other_options_div .fieldcontainer, #select_reocvery_email .fieldcontainer { width: auto; margin: 0 -40px; margin-bottom: 40px; } .text16 { display: block; text-align: center; margin-bottom: 30px; color: #626262; font-size: 16px; font-weight: 500; text-decoration: none; } .pointer { cursor: pointer; } .pass_policy { color: #8c8c8c; font-size: 14px; padding-top: 10px; } .nomargin { display: block; margin: 0px; } .tryanother, .extra_options { width: fit-content; margin: 0 auto; cursor: pointer; margin-top: 20px; } .bluetext_action { display: inline-block; font-size: 14px; color: #159aff; font-weight: 500; line-height: 16px; cursor: pointer; margin-top: 5px; } .nonclickelem { color: #626262; pointer-events: none; cursor: none; } .bluetext_action a { text-decoration: none; } .recovery_container { display: block; width: 480px; height: 350px; background-color: #fff; box-shadow: 0px 2px 30px 0px #2b2b2b17; margin: auto; position: relative; z-index: 1; overflow: hidden; } .recovery_box { width: 480px; min-height: 500px; height: auto; background: #fff; box-sizing: border-box; padding: 40px 40px; border-radius: 2px; transition: all 0.1s ease-in-out; float: left; overflow-y: auto; display: table-cell; border-right: 2px solid #f1f1f1; } .menuicon { display: inline-block; float: left; height: 14px; width: 14px; padding: 14px; font-size: 14px; text-align: center; } .user_info { display: inline-flex; justify-content: space-between; border: 1px solid #eeeeee; margin-bottom: 20px; border-radius: 7px; cursor: pointer; box-sizing: border-box; max-width: 100%; flex-wrap: nowrap; } .user_info_space { margin-top: 20px; } .support_temp_info { margin-bottom: 30px; line-height: 24px; } .menutext { display: inline-block; font-size: 16px; padding: 12px 14px; line-height: 20px; width: auto; word-break: break-all; } .fieldcontainer { margin-bottom: 40px; } .change_user { position: relative; float: right; font-size: 14px; padding: 0px 14px 0px 0px; display: inline-block; color: #0091ff; line-height: 38px; font-weight: 500; display: flex; align-items: center; justify-content: center; } .info_head { display: block; font-size: 20px; font-weight: 500; margin-bottom: 20px; line-height: 30px; overflow: auto; transition: all 0.1s ease-in-out; } .info_head #headtitle { display: block; } .head_info { font-size: 16px; margin: 10px 0px 0px 0px; line-height: 24px; font-weight: 400; color: #000000e6; } .user_info_space + .head_info { margin: 0px; } .otp_container { display: block; width: 100%; height: 54px; box-sizing: border-box; border-radius: 2px; font-size: 16px; outline: none; padding: 0px 15px; transition: all 0.2s ease-in-out; background: #f9f9f9; border: 1px solid #dddddd; text-indent: 0px; } .customOtp { border: none; outline: none; background: transparent; height: 100%; font-size: 16px; text-align: left; width: 22px; padding: 0px; } .textindent42 { text-indent: 46px; } .textindent62 { text-indent: 56px; } .textintent52 { text-indent: 51px; } .box_header_load { display: block; height: auto; padding: 50px 0px; -webkit-animation-name: blink; /* Safari 4.0 - 8.0 / -webkit-animation-duration: 1s; / Safari 4.0 - 8.0 */ animation-name: blink; animation-duration: 1s; animation-iteration-count: infinite; animation-timing-function: linear; opacity: 0.05; } .box_head_load { display: block; width: 180px; height: 18px; border-radius: 8px; background-color: #000; } .blink_btn { -webkit-animation-name: blink; /* Safari 4.0 - 8.0 / -webkit-animation-duration: 1s; / Safari 4.0 - 8.0 */ animation-name: blink; animation-duration: 1s; animation-iteration-count: infinite; animation-timing-function: linear; opacity: 0.05; } .box_define_load { display: block; max-width: 800px; width: 100%; height: 16px; border-radius: 8px; background-color: #000; margin-top: 20px; } @keyframes blink { 0% { opacity: 0.08; } 50% { opacity: 0.01; } 100% { opacity: 0.08; } } #loading_div, #Last_password_div, #mobile_confirm_div, #email_confirm_div, #confirm_otp_div, #other_options_div, #contact_support_div, #change_password_div, #recovery_device_div, #password_matched_div, #username_div, #terminate_session_div { display: none; } #multiple_reocvery_mobile, #single_reocvery_mobile, #multiple_reocvery_email, #single_reocvery_email { display: none; } .verify_mob_container, .verify_email_container, .select_device_othermodes { display: none; } .devices { position: relative; padding: 0px; width: fit-content !important; width: -moz-fit-content !important; width: -webkit-fit-content !important; margin: auto; border-radius: 8px; box-sizing: border-box; margin-bottom: 30px; background: #fcfcfc; } .device_title { position: absolute; top: 12px; left: 48px; font-size: 10px; font-weight: 600; text-transform: uppercase; color: #000000b3; line-height: 14px; z-index: 11; } .select2-container--device_select { margin: 0px; display: block; position: relative; margin: auto; cursor: pointer; border: 1px solid #dddddd; border-radius: 8px; overflow: hidden; } #recovery_device_select + .select2-container { width: fit-content !important; width: -moz-fit-content !important; width: -webkit-fit-content !important; } .select2-container--device_select .select2-selection__arrow { position: absolute; top: 0px; right: 14px; width: auto; height: 100%; } .select2-container--device_select .select2-selection__arrow b { border-color: transparent #00000066 #00000066 transparent; border-style: solid; transform: rotate(45deg); border-width: 2px; height: 4px; width: 4px; position: relative; border-radius: 1px; display: inline-block; top: 24px; } .select2-container--device_select .selection { margin: auto; height: 60px; box-sizing: border-box; min-width: 140px; } .select2-container--device_select .select2-selection { height: unset; padding: 12px 34px 12px 14px; } .select2-container--device_select .select_con { font-weight: 400; margin-left: 12px; margin-top: 16px; } .select2-container--device_select .select_icon { margin-top: 7px; } .select2-results__options { margin: 0px; } .select2-results__options .select_con { margin: 0px; } .select2-dropdown .select_con { width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .hideArrow .select2-selection { cursor: default; padding: 12px 14px; } .hideArrow .select2-selection__arrow { display: none; } .secondary_devices { display: none; width: 150px; margin: auto; padding: 8px 18px; border-radius: 18px; background-color: #f4f6f8; border: none; overflow: hidden; max-width: 200px; text-overflow: ellipsis; font-size: 16px; outline: none; } .secondary_devices .select2-container--open { width: 200px; } .device_select { display: block; position: unset; width: auto !important; } .device_selection { padding: 8px 14px; border-radius: 18px; } .deviceparent { text-align: center; display: none; text-overflow: ellipsis; overflow: hidden; width: 100%; white-space: nowrap; } .deviceparent { display: block; } .deviceinfo { display: inline-block; } .devicetext { margin: 0 auto; margin-left: 30px; } .select_icon { float: left; font-size: 20; color: #499aff; } .select_con { float: left; width: auto; overflow: hidden; margin-left: 5px; text-overflow: ellipsis; } .options_selct { max-width: 180px; font-size: 14px; line-height: 20px; font-weight: 500; width: auto; } .contact_support_class { min-height: unset; } .contact_support_class .recovery_box { min-height: unset; } #mfa_totp_section { display: none; } /* Terminate_session page */ #terminate_session_form { overflow: auto; } #terminate_session_form .checkbox_div { position: relative; } #terminate_session_form .checkbox_check { position: absolute; z-index: 1; opacity: 0; left: 15px; margin: 0px; height: 16px; cursor: pointer; width: 16px; } #terminate_session_form .checkbox { float: left; z-index: 0; height: 12px; width: 12px; display: inline-block; border: 2px solid #ccc; border-radius: 2px; position: relative; top: 1.5px; overflow: hidden; background-color: #fff; } #terminate_session_form .checkbox_check:hover ~ .checkbox { border: 2px solid #159aff; } #terminate_session_form .checkbox_check:checked ~ .checkbox { background-color: #159aff; border-color: #159aff; } #terminate_session_form .checkbox .checkbox_tick { display: block; height: 3px; width: 8px; border-bottom: 2px solid #fff; border-left: 2px solid #fff; transform: rotate(-45deg); margin: 2px 1px; } #terminate_session_form .checkbox_label { cursor: pointer; margin: 0px 6px; line-height: 20px; width: 85%; display: inline-block; } #terminate_session_form .showOneAuthLable { border: 1px solid #e7e7e7; border-radius: 10px 10px 0px 0px; box-sizing: border-box; max-width: 420px; } .oneAuthLable { display: inline-flex; max-width: 420px; padding: 15px; align-items: center; box-sizing: border-box; border: 1px solid #e7e7e7; border-top: none; border-radius: 0px 0px 15px 15px; } .oneauth_icon { display: inline-block; width: 40px; height: 40px; border-radius: 14px; background-size: 40px 40px; } .one_auth_icon_v2 { background-image: url(../images/oneAuth2.4b2a6945d5ecd70b703ba18f5f11eb68.png); } .oneAuthLable .text_container { flex: 1; margin: 0px 10px; } .oneAuthLable .text_header { font-size: 12px; font-weight: 500; margin-bottom: 4px; } .oneAuthLable .text_desc { font-size: 10px; line-height: 14px; } .oneAuthLable .togglebtn_div { height: 16px; padding: 4px; width: 30px; display: inline-block; position: relative; } .oneAuthLable .real_togglebtn { cursor: pointer; display: inline-block; position: relative; height: 16px; width: 30px; z-index: 1; opacity: 0; position: absolute; margin: 0px; } .real_togglebtn:checked ~ .togglebase { background-color: #10bc83; } .real_togglebtn:checked ~ .togglebase .toggle_circle { left: 16px; } .oneAuthLable .togglebase { height: 16px; width: 30px; display: inline-block; background: #ccc; border-radius: 10px; position: absolute; } .oneAuthLable .toggle_circle { transition: all 0.2s ease-in-out; height: 12px; width: 12px; background-color: #fff; border-radius: 10px; display: inline-block; position: absolute; left: 2px; top: 2px; box-shadow: 0px 0px 5px #999; } @media only screen and (max-width: 600px) { body { -webkit-tap-highlight-color: rgba(255, 255, 255, 0); } .bg_one { display: none; } .alert_message, .error_message { max-width: 300px; width: 75%; } .Alert, .Errormsg { max-width: 400px !important; padding: 0px; min-width: 300px; } .textbox, .otp_container { background-color: transparent; border: none; border-bottom: 2px solid #f4f6f8; border-radius: 0px; } .textbox { transition: unset; } .textbox:-webkit-autofill, .textbox:-webkit-autofill:hover, .textbox:-webkit-autofill:focus, .textbox:-webkit-autofill:active { -webkit-box-shadow: inset 0 0 0px 9999px white; -webkit-text-fill-color: black; } .textbox:valid, .textbox:hover { border: none; border-bottom: 2px solid #159aff; } #captcha { border-radius: 2px; outline: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; } .changeloadbtn { border-radius: 22px; } .btn { margin-top: 10px; border-radius: 4px; } .mini_btn { margin-top: 0px; } .optionstry:hover { background-color: #fff; } .img_option { margin: 0px 10px 0px 0px !important; } .option_details_try { color: #555555; display: inline-block; margin: 0px; } #multiple_reocvery_mobile .fieldcontainer, #multiple_reocvery_email .fieldcontainer, #other_options_div .fieldcontainer { margin: 0 -30px; margin-bottom: 40px; } .optionmod { margin-left: 0px; padding: 15px 30px; line-height: 24px; } .recovery_box { width: 100%; padding: 0px 30px; height: auto; border-right: none; padding-bottom: 40px; } .recovery_container { width: 100%; box-shadow: none; margin: 0 auto; position: relative; z-index: 1; margin-top: 40px; height: auto; overflow: hidden; } .info_head { margin-bottom: 30px; } } .devices .select2-container--open { background: transparent; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .restrict_icon { background: url(../images/URLError2x.5e762e74a83ee0cda60b8f7c9df299a8.png) no-repeat transparent center/auto 100%; } } .hide { display: none; } .hover-tool-tip { position: absolute; top: 15px; left: 335px; background: #fff; padding: 20px; box-shadow: 0px 0px 10px #0000001a; transition: opacity 0.1s; border-radius: 5px; z-index: 9; opacity: 0; } .hover-tool-tip::after { content: ""; position: absolute; width: 0; height: 0; margin-left: -8px; top: 25px; left: 0; box-sizing: border-box; border: 6px solid black; border-color: #ffffff transparent transparent #ffffff; transform-origin: 0 0; transform: rotate(-45deg); box-shadow: -6px -6px 10px 0 #0000001a; } .hover-tool-tip.no-arrow::after { content: none; } .hover-tool-tip ul { padding: 0; margin: 0px 0px 0px 15px; list-style: none; } .hover-tool-tip p { margin: 0px 0px 10px 0px; font-size: 14px; font-weight: 500; } .hover-tool-tip ul li { font-size: 12px; display: flex; align-items: center; white-space: nowrap; line-height: 25px; } .hover-tool-tip ul li.success::before { background-color: #0dbc83; } .hover-tool-tip ul li::before { margin-right: 10px; background-color: red; width: 8px; height: 8px; border-radius: 50%; } .titlename { display: none !important; } /* #lookup_div { display: none !important; } */ #lookup_div .head_info { font-size: 0; } #lookup_div .head_info::before { content: "Enter your email address"; font-size: 15px; } .info_head { padding-top: 20px; } .rec_modes_other_options { display: none !important; } .recovery_container { height: 29rem; } .Last_password_div { margin-top: -30px; } ``` 以下のコードをコピーして、IDEを使用してクライアントディレクトリ(`birthdaygreetings/src/components/`)内の各ファイルに貼り付けて保存します。 **form.css** ```css .form-container { display: grid; height: 190px; grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; gap: 20px; padding: 20px; max-width: 786px; margin: 75px auto; box-shadow: 0 4px 8px rgb(0 0 0 / 10%); border-radius: 8px; background-color: #fff; } .form-group { width: 100%; height: 0px; display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 42px; margin-bottom: 57px; } label { font-size: 19px; font-weight: bold; width: 123px; } input { font-size: 13px; padding: 8px; border: 1px solid #ccc; border-radius: 4px; flex: 1; } input:focus { border-color: #007bff; outline: none; box-shadow: 0 0 4px rgba(0, 123, 255, 0.25); } .form-container > .form-group:nth-child(1) { grid-column: 1; grid-row: 1; } .form-container > .form-group:nth-child(2) { grid-column: 2; grid-row: 1; } .form-container > .form-group:nth-child(3) { grid-column: 1; grid-row: 2; } .form-container > .form-group:nth-child(4) { grid-column: 2; grid-row: 2; } .submit-form{ height: 50px; width: 100%; margin-bottom: 64px; } .submit-btn{ background-color: #58d358; border: none; border-radius: 10px; color: #fff; font-size: 20px; height: 46px; margin-left: 42%; width: 16%; } ``` **form.jsx** ```js import { useState } from "react"; import "./form.css"; function Form({ onSubmit }) { const [formData, setFormData] = useState({ name: "", birthday: "", message: "", email: "", }); const handleChange = (e) => { const { id, value } = e.target; setFormData({ ...formData, [id]: value }); }; const handleSubmit = (e) => { e.preventDefault(); onSubmit(formData); }; const today = new Date().toISOString().split("T")[0]; return ( <> <form onSubmit={handleSubmit}> <div className="form-container"> <div className="form-group"> <label htmlFor="name">Name</label> <input type="text" id="name" value={formData.name} onChange={handleChange} /> </div> <div className="form-group"> <label htmlFor="birthday">Birthday</label> <input type="date" id="birthday" value={formData.birthday} onChange={handleChange} max={today} /> </div> <div className="form-group"> <label htmlFor="message">Message</label> <input type="text" id="message" value={formData.message} onChange={handleChange} /> </div> <div className="form-group"> <label htmlFor="email">Email</label> <input type="email" id="email" value={formData.email} onChange={handleChange} /> </div> </div> <div className="submit-form"> <button className="submit-btn" type="submit"> Submit </button> </div> </form> </> ); } export default Form; ``` **modal.css** ```css .modal { display: flex; justify-content: center; align-items: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 1000; padding: 20px; box-sizing: border-box; } .modal-content { background-color: #fff; padding: 20px; border-radius: 8px; width: 100%; max-width: 500px; position: relative; box-shadow: 0px 2px 15px rgba(0, 0, 0, 0.1); } .edit-heade{ width: 100%; height: 60px; display: flex; } .modal-header h2{ padding-left: 185px; font-size: 1.5rem; margin-bottom: 20px; } .modal-close { position: absolute; top: 10px; right: 15px; font-size: 1.5rem; cursor: pointer; color: #333; } .modal-input-group { margin-bottom: 15px; } .modal-label { font-weight: 700; font-weight: bold; display: block; margin-bottom: 5px; } .modal-input { width: 89%; padding: 10px; border-radius: 5px; border: 1px solid #ccc; font-size: 1rem; } .modal-submit { text-align: center; } .modal-button { background-color: #4CAF50; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 1rem; transition: background-color 0.3s; } .modal-button:hover { background-color: #45a049; } ``` **modal.jsx** ```js import { useState } from "react"; import "./modal.css" function Modal({ editData, onUpdate, onClose }) { const [formData, setFormData] = useState(editData); const handleChange = (e) => { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); }; const handleSubmit = () => { onUpdate(formData); }; const today = new Date().toISOString().split("T")[0]; return ( <div className="modal"> <div className="modal-content"> <div className="edit-header"> <div className="modal-header"> <h2>Edit Greeting</h2> </div> <div className="modal-close"> <button onClick={onClose}>×</button> </div> </div> <div className="modal-input-group"> <input name="Name" value={formData.Name} onChange={handleChange} className="modal-input" /> </div> <div className="modal-input-group"> <input name="Message" value={formData.Message} onChange={handleChange} className="modal-input" /> </div> <div className="modal-input-group"> <input name="BirthDay" type="date" value={formData.BirthDay} onChange={handleChange} className="modal-input" max={today} // 最大日付を今日に設定 /> </div> <div className="modal-input-group"> <input name="Email" value={formData.Email} onChange={handleChange} className="modal-input" /> </div> <div className="modal-submit"> <button className="modal-button" onClick={handleSubmit}>Update</button> </div> </div> </div> ); } export default Modal; ``` **toggleSwitch.css** ```css .switch { display: block; position: relative; display: inline-block; width: 34px; height: 20px; } .switch input { opacity: 0; width: 0; height: 0; } .slide { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: 0.4s; border-radius: 20px; } .slide:before { position: absolute; content: ""; height: 14px; width: 14px; left: 3px; bottom: 3px; background-color: white; transition: 0.4s; border-radius: 50%; } input:checked + .slide { background-color: #2196f3; } input:checked + .slide:before { transform: translateX(14px); } ``` **ToggleSwitch.jsx** ```js import "./toggleSwitch.css" function ToggleSwitch({ isChecked, onToggle }) { return ( <label className="switch"> <input type="checkbox" checked={isChecked} onChange={(e) => onToggle(e.target.checked)} /> <span className="slide round"> </span> </label> ); } export default ToggleSwitch; ``` **topBar.css** ```css body{ margin: 0; padding: 0; } .topbarContainer{ height: 50px; width: 100%; background-color: rgb(58, 58, 98); display: flex; align-items: center; position: fixed; top: 0; z-index: 999; } .topbarLeft{ flex: 1 1; display: flex; align-items: center; gap: 22%; padding-left: 29px; } .naviagtion-btn{ height: 30px; background-color: white; border: none; border-radius: 7px; font-size: 14px; font-weight: 600; } .topLogo{ font-size: 24px; margin-left: 15px; color: white; cursor: pointer; } .topBarCenter{ flex: 1 1; color: white; padding-left: 8%; } .topbarRight{ flex: 0 1; display: flex; justify-content: space-between; padding-left: 24%; } .topRight-btn{ width: 74px; height: 31px; font-size: 15px; font-weight: 650; background-color: red; color: white; margin-right: 40px; border: none; border-radius: 7px; } .topbarlink{ display: flex; margin-left: 67px; color: white; } ``` **TopBar.jsx** ```js import React, { useCallback } from 'react' import "./topBar.css" import { Link } from 'react-router-dom' export default function TopBar() { const logout = useCallback(() => { window.catalyst.auth.signOut('/'); }, []); return ( <> <div className="topbarContainer"> <div className="topbarLeft"> <Link to="/addUserPage"> <button className='naviagtion-btn'>Add New Greetings</button> </Link> <Link to="/ListUsers"> <button className='naviagtion-btn'>Greetings List</button> </Link> </div> <div className="topBarCenter"> <div className="seacrhbar"> <h1>Birthday Greetings</h1> </div> </div> <div className="topbarRight"> <button className="topRight-btn" onClick={logout}>Log Out</button> </div> </div> </> ) } ``` **Userlist.css** ```css .users-container { display: flex; flex-direction: column; gap: 8px; } .users-lists { width: 88%; padding: 15px; border: 1px solid #ccc; border-radius: 22px; background-color: #f9f9f9; margin-left: 80px; margin-bottom: 34px; display: flex; flex-direction: column; align-items: flex-start; } .user-item { width: 100%; display: flex; align-items: center; justify-content: space-between; } .left-content { display: flex; flex-direction: column; } .left-content span { margin-bottom: 8px; } .name { font-size: 28px; font-weight: bold; } .date, .email { font-size: 16px; } .message { font-size: 20px; } .right-button { display: flex; align-items: center; gap: 20px; width: 25%; justify-content: flex-end; } .edit-btn, .delete-btn { width: 70px; height: 34px; border-radius: 10px; color: white; border: none; } .edit-btn { background-color: black; } .delete-btn { background-color: rgb(255, 0, 0); } ``` **UserList.jsx** ```js import ToggleSwitch from "./ToggleSwitch"; import "./UserList.css"; function UserList({ users, onEdit, onDelete, onToggle }) { return ( <div className="users-container"> {users.map((user) => ( <div className="users-lists" key={user.ID}> <div className="user-item"> <div className="left-content"> <span className="name">{user.Name}</span> <span className="date">{user.BirthDay}</span> <span className="message">{user.Message}</span> <span className="email">{user.Email}</span> </div> <div className="right-button"> <ToggleSwitch isChecked={user.AutoSend} onToggle={(checked) => onToggle(user.ID, checked)} /> <button className="edit-btn" onClick={() => onEdit(user.ID)}>Edit</button> <button className="delete-btn" onClick={() => onDelete(user.ID)}>Delete</button> </div> </div> </div> ))} </div> ); } export default UserList; ``` 以下のコードをコピーして、IDEを使用してクライアントディレクトリ(`birthdaygreetings/src/`)内の各ファイルに貼り付けて保存します。 **App.css** ```css body { margin: 0; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; background-color: #ffffff; height: inherit; } .inputs { width: 90%; padding: 15px; margin: 15px 0 22px 0; display: inline-block; border: none; background: #f1f1f1; border-radius: 8px; } h1, h2, h3, h4, h5, h6, p { margin: 1; } #login { height: 29rem; } .Header{ display: flex; align-items: center; gap: 54%; } ``` **App.js** ```js import { HashRouter, Routes, Route, Navigate } from "react-router-dom"; import Layout from "./Layout"; import Signup from "./SignUp"; import ListUsers from "./ListUsers"; import UserProfile from "./UserProfile"; function App() { return ( <HashRouter> <Routes> <Route path="/" element={<Layout />} /> <Route path="/signup" element={<Signup />} /> <Route path="/addUserPage" element={<UserProfile />} /> <Route path="/ListUsers" element={<ListUsers />} /> <Route path="" element={<Navigate to="/" replace />} /> <Route path="*" element={<Navigate to="/" replace />} /> </Routes> </HashRouter> ); } export default App; ``` **index.css** ```css body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ``` **index.js** ```js import "./App.css"; import React from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; const container = document.getElementById("root"); const root = createRoot(container); root.render( <React.StrictMode> <App /> </React.StrictMode> ); ``` **Layout.js** ```js import UserProfile from "./UserProfile"; import LoginPage from "./LoginPage.js"; import { useEffect, useState } from "react"; function Layout() { const [isFetching, setIsFetching] = useState(true); const [isUserAuthenticated, setIsUserAuthenticated] = useState(false); const [userDetails, setUserDetails] = useState({ firstName: "", lastName: "", mailid: "", timeZone: "", createdTime: "", }); useEffect(() => { window.catalyst.auth.isUserAuthenticated().then((result) => { setUserDetails({ firstName: result.content.first_name, lastName: result.content.last_name, mailid: result.content.email_id, timeZone: result.content.time_zone, createdTime: result.content.created_time, }); setIsUserAuthenticated(true); }) .catch((err) => {}) .finally(() => { setIsFetching(false); }); }, []); return ( <> {isFetching ? ( <p>Loading ….</p> ) : isUserAuthenticated ? ( <UserProfile userDetails={userDetails} /> ) : ( <LoginPage /> )} </> ); } export default Layout; ``` **ListUsers.js** ```js import { useState, useEffect } from "react"; import axios from "axios"; import UserList from "./components/UserList"; import Modal from "./components/modal"; import TopBar from "./components/TopBar"; function ListUsers() { const [users, setUsers] = useState([]); const [editData, setEditData] = useState(null); const [isModelOpen, setModal] = useState(false); const fetchUsers = async () => { try { const response = await axios.get("/server/advance_function/getReminder"); setUsers(response.data); } catch (error) { console.error("Error fetching users:", error); } }; useEffect(() => { fetchUsers(); }, []); const handleEdit = (id) => { const userToEdit = users.find((user) => user.ID === id); setEditData(userToEdit); setModal(true); }; const handleUpdate = async (updatedData) => { try { await axios.put("/server/advance_function/updateReminder", updatedData); alert("User updated successfully!"); setEditData(null); setModal(false); fetchUsers(); } catch (error) { console.error("Error updating user:", error); } }; const handleDelete = async (id) => { if (window.confirm("Are you sure you want to delete this birthday wish?")) { try { await axios.delete(`/server/advance_function/deleteReminder/${id}`); setUsers(users.filter((user) => user.ID !== id)); alert("User deleted successfully!"); } catch (error) { console.error("Error deleting user:", error); } } }; const handleToggle = async (ID, checked) => { const AutoSendStatus = checked ? "enable" : "disable"; try { await axios.patch("/server/advance_function/toggleAutoSend", { id: ID, status: AutoSendStatus, }); setUsers((prevUsers) => prevUsers.map((user) => user.ID === ID ? { ...user, AutoSend: checked } : user ) ); } catch (error) { console.error("Error toggling the user:", error); } }; return ( <> <div > <TopBar /> </div> <div className="userlist-div" style={{height: "calc(100vh - 60px)",margin: "60px 0 0"}}> <UserList users={users} onEdit={handleEdit} onDelete={handleDelete} onToggle={handleToggle} /> {isModelOpen && ( <Modal editData={editData} onUpdate={handleUpdate} onClose={() => setModal(false)} /> )} </div> </> ); } export default ListUsers; ``` **LoginPage.js** ```js import { useEffect } from "react"; import { Link } from "react-router-dom"; const LoginPage = () => { useEffect(() => { // 設定はオプションです const config = { css_url: "/app/embeddediframe.css", // ログインページのカスタマイズCSSファイルパス(未指定の場合はデフォルトCSSが適用されます) is_customize_forgot_password: false, // デフォルト値はfalseです。パスワードリセットページをカスタマイズする場合はtrueに設定してください forgot_password_id: "login", // パスワードリセットページを読み込む要素ID(デフォルト: "loginDivElementId") forgot_password_css_url: "/app/fpwd.css", // パスワードリセットページのカスタマイズCSSファイルパス(未指定の場合はデフォルトCSSが適用されます) }; window.catalyst.auth.signIn("login", config); }, []); return ( <div className="container"> <center> <h1 className="title">Birthday Greetings</h1> </center> <div id="login"></div> <p className="homepage"> <b> Don't have an account?{" "} <Link to="/signup" style={{ color: "blue", textDecorationLine: "underline" }}> Sign-up </Link>{" "} now! </b> </p> </div> ); }; export default LoginPage; ``` **SignUp.css** ```css input[type="submit"] { background-color: green; color: white; width: 40%; padding: 8px; border-radius: 8px; text-align: center; border: none; cursor: pointer; } #link { font-size: medium; color: blue; } .modal-content { background-color: #c0c0c0; margin: 30px auto; } .signupfnbtn { width: 30%; padding: 8px; border-radius: 8px; background-color: green; height: 100%; } p { text-align: center; font-size: medium; font-weight: bold; } ``` **SignUp.js** ```js import "./SignUp.css"; import React, { useState } from "react"; function Signup() { const [displayText, setDisplayText] = useState(""); const [form, setForm] = useState({ firstName: "", lastName: "", email: "", }); const [showForm, setShowForm] = useState(true); const handleSubmit = async (event) => { event.preventDefault(); setShowForm(false); setDisplayText( "An account verification email has been sent to your email address" ); const data = { first_name: form.firstName, last_name: form.lastName, email_id: form.email, platform_type: "web", }; try { const auth = window.catalyst.auth; const signupResponse = await auth.signUp(data); if (signupResponse.status === 200) { setTimeout(() => { window.location.href = "index.html"; }, 3000); } else { alert(signupResponse.message); } } catch (error) { console.error("Error during signup:", error); alert("An error occurred during signup. Please try again."); setShowForm(true); // エラーがある場合はフォームを再表示 } }; const handleInputChange = (e) => { const { name, value } = e.target; setForm((prevForm) => ({ ...prevForm, [name]: value, })); }; return ( <div id="signup" className="signup"> {showForm ? ( <div> <center> <img width="80px" height="80px" src="https://cdn2.iconfinder.com/data/icons/user-management/512/profile_settings-512.png" alt="User Profile" /> <h1>User Profile Management</h1> </center> <form onSubmit={handleSubmit} className="modal-content"> <center> <h1>Sign Up</h1> <p>Please fill this form to sign up for a new account.</p> </center> <label htmlFor="firstName"> <b>First Name</b> <input name="firstName" className="inputs" placeholder="Enter First Name" value={form.firstName} onChange={handleInputChange} required /> </label> <label htmlFor="lastName"> <b>Last Name</b> <input name="lastName" className="inputs" placeholder="Enter Last Name" value={form.lastName} onChange={handleInputChange} required /> </label> <label htmlFor="email"> <b>Email</b> <input name="email" className="inputs" placeholder="Enter email address" value={form.email} onChange={handleInputChange} required /> </label> <p> By creating an account, you agree to our{" "} <a href="https://www.zoho.com/catalyst/terms.html" target="_blank" rel="noopener noreferrer" id="link" > Terms & Conditions </a> . </p> <center> <input type="submit" value="Sign Up" className="signupfnbtn" /> </center> </form> </div> ) : ( <p>{displayText}</p> )} </div> ); } export default Signup; ``` **UserProfile.css** ```css .app-container{ overflow: auto; } ::-webkit-scrollbar{ width: 5px; } ::-webkit-scrollbar-track{ background-color: rgb(34, 34, 59); } ::-webkit-scrollbar-thumb{ background-color: rgb(150, 150, 150); } .Header{ display: flex; align-items: center; gap: 54%; } ``` **UserProfile.js** ```js import "./UserProfile.css"; import axios from "axios"; import Form from "./components/form"; import TopBar from "./components/TopBar"; function UserProfile() { const handleSubmit = async (formData) => { try { await axios.post("/server/advance_function/insertReminder",formData); alert("Reminder added successfully!"); window.location.reload(); } catch (error) { console.error("Error submitting form:", error); } }; return ( <div className="app-container"> <div className="Header"> <TopBar /> </div> <div className="form-div"> <Form onSubmit={handleSubmit} /> </div> </div> ); } export default UserProfile; ``` 以下に示すように、`birthdaygreetings/`ディレクトリにある`client-package.json`ファイルを更新します。 **client-package.json** ```json { "name": "birthdaygreetings", "version": "0.0.1", "homepage": "index.html", "login_redirect": "index.html" } ``` クライアントディレクトリの設定が完了しました。 アプリケーションのビジネスロジックを確認しましょう。 - **認証**: - アプリケーションの最初のページはログインページです。ログインページに加えて、ユーザーには新しいアカウントの作成や既存のアカウントのパスワードリセットのオプションが提供されます。 - ユーザーは、Custom User Validation関数にコーディングされた条件を満たした場合にのみアカウントを作成できます。 - アカウントの登録に成功すると、メールに送信される確認リンクを使用してアカウントを確認する必要があります。 - アカウントを確認し、有効なパスワードを作成すると、アプリにログインしてアプリケーションの使用を開始できます。 - **cronのスケジューリング**(リマインダーの作成): - エンドユーザーは、以下の詳細を入力して誕生日グリーティングを作成します: - 名前 - 生年月日 - カスタムメッセージ - 受信者のメールアドレス - これらの詳細が送信されると、Dynamic Cronが作成され、誕生日の日付に毎年ジョブプールに定期的なジョブを送信するようにスケジュールされます。 - **リマインダーの管理**: - 必要なリマインダーを作成した後、アプリケーションでリマインダーの一覧を表示できます。リマインダーの無効化、編集、削除も可能です。 - 無効化アクションはトグルで処理されます。デフォルトでは有効になっています。無効にした場合、または何らかの方法で更新した場合、変更はData Storeに更新され、Dynamic Cronは新しい要件に応じて自動的に調整されます。 - **ログアウト機能**: - 最後に、必要なすべての操作が完了したら、安全にアプリケーションからログアウトできます。