1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

戸締り確認の不安を解消するPWAアプリを作ってみた

Last updated at Posted at 2019-08-13

はじめに

初めての投稿になります。よろしくお願いしますm(_ _)m。

結論としてタイトルの結果、完成したのが以下のウェブアプリです。基本的にスマホから見るのでブラウザ越しなのですが、PWA アプリに対応しているのでホーム画面に張り付けても使えます。

戸締り確認くん

日本語の表示

20190812_01.png

英語の表示

20190812_02.png

これは以前、Togetter で見かけた記事 を見て、これがスマホアプリだったらいいのに・・・と思っていたことがきっかけでこの度チャレンジしてみました。

構成

静的サイトオンリーで作っています。サーバーサイドはもうちょっと勉強しないと分からないです。

基本

  • HTML, CSS, JavaScript
  • bootstrap
  • bootstrap-toggle
  • js.cookie.js

その他

  • PWA 対応
  • Google Analytics
  • GDPR
  • Netlify
  • 日本語、英語切り替え

アイディア自体はすごくシンプルで、各項目を表形式で表示させて、各項目に対してオンオフボタンと、ボタンを押したときの更新日を表示させるだけです。後はこれを保存したり更新したりすれば出来上がり!という仕様です。

自分は元々 C#/VB でデスクトップ開発していたので、そんなにウェブ系には明るくありませんでした。でもこの仕様でいけると思ったので、HTML を勉強中の身でも作れるのは?と思いました。

後はググって使い方覚えて組み合わせて組み込む。のループでした。完成した今見返してみると、全体的に初級レベルだと思うのですが、作っている最中は1つ1つが知らないことだったので、初心者なりに苦労してつまづいていたりしました。

ちなみに、ググった結果多く参考にさせていただいたサイトがこの Qiita でした。本当に皆様のおかげです!ありがとうございます!優しい世界!

技術的な話

本当におこがましいのですが、アイディアがあって無いようなものですので、せめてソースコードを載せて還元させていただこうかと思います。完全ソースではなく、主要部分のみ抜粋です。

index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>戸締まり確認くん</title>
        <link rel="stylesheet" href="css/bootstrap.css">
        <link rel="stylesheet" href="css/bootstrap4-toggle.css">
        <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
        <script type="text/javascript" src="js/bootstrap.bundle.js"></script>
        <script type="text/javascript" src="js/bootstrap4-toggle.js"></script>
        <script type="text/javascript" src="js/js.cookie.js"></script>
        <script type="text/javascript" src="js/main.js"></script>
    </head>
    <body>
        <div class="container">

            <h1 id="title">戸締まり確認くん</h1>
            <div>
                <ul class="list-inline">
                    <li class="list-inline-item"><a href="" onclick="toEnglish()">English</a></li>
                    <li class="list-inline-item"><a href="" onclick="toJapanese()">日本語</a></li>
                </ul>
            </div>
            <br>

            <p id="description">On/Off データはブラウザの Cookie(30日間)として保存・表示しています。手動で切り替えてお使いください。</p>
            <br>

            <h2 id="normal">日常</h2>
            <table class="table table-striped">
                <tr>
                    <td><label id="lbl1a"></label></td>
                    <td><input type="checkbox" id="chk1" data-toggle="toggle" data-width="80" data-on="OK" data-off="NG"></td>
                    <td><label id="lbl1b">        </label></td>
                </tr>
                <tr>
                    <td><label id="lbl2a"></label></td>
                    <td><input type="checkbox" id="chk2" data-toggle="toggle" data-width="80" data-on="OK" data-off="NG"></td>
                    <td><label id="lbl2b"></label></td>
                </tr>
                <tr>
                    <td><label id="lbl3a"></label></td>
                    <td><input type="checkbox" id="chk3" data-toggle="toggle" data-width="80" data-on="OK" data-off="NG"></td>
                    <td><label id="lbl3b"></label></td>
                </tr>
                <tr>
                    <td><label id="lbl4a"></label></td>
                    <td><input type="checkbox" id="chk4" data-toggle="toggle" data-width="80" data-on="OK" data-off="NG"></td>
                    <td><label id="lbl4b"></label></td>
                </tr>
            </table>
            <br>

            <h2 id="vacation">長期留守</h2>
            <table class="table table-striped">
                <tr>
                    <td><label id="lbl5a"></label></td>
                    <td><input type="checkbox" id="chk5" data-toggle="toggle" data-width="80" data-on="OK" data-off="NG"></td>
                    <td><label id="lbl5b">        </label></td>
                </tr>
                <tr>
                    <td><label id="lbl6a"></label></td>
                    <td><input type="checkbox" id="chk6" data-toggle="toggle" data-width="80" data-on="OK" data-off="NG"></td>
                    <td><label id="lbl6b"></label></td>
                </tr>
                <tr>
                    <td><label id="lbl7a"></label></td>
                    <td><input type="checkbox" id="chk7" data-toggle="toggle" data-width="80" data-on="OK" data-off="NG"></td>
                    <td><label id="lbl7b"></label></td>
                </tr>
            </table>

        </div>
    </body>
</html>
main.js

var toEnglish = function() {
    Cookies.set('isEnglish', true, {expires: 30});
    location.reload();
};

var toJapanese = function() {
    Cookies.set('isEnglish', false, {expires: 30});
    location.reload();
};

$(function() {
    
    var isEnglish = Cookies.get('isEnglish');
    if (isEnglish == undefined || isEnglish == 'false') {
        isEnglish = false;
    } else {
        isEnglish = true;
    }

    if (isEnglish) {
        document.title = "Closed door confirmation";
        document.getElementById('title').textContent = "Closed door confirmation";
        document.getElementById('description').textContent = "On / Off data is stored and displayed as browser cookies (30 days). Please switch it manually.";
        document.getElementById('normal').textContent = "Normal:";
        document.getElementById('vacation').textContent = "Long vacation:";
    }

    var zeroFormat = function(x) {
        return x.toString().padStart(2, '0');
    };

    var weeks = ['(日)', '(月)', '(火)', '(水)', '(木)', '(金)', '(土)'];
    if (isEnglish) {
        weeks = ['(Sun)', '(Mon)', '(Tue)', '(Wed)', '(Thu)', '(Fri)', '(Sut)'];
    }

    var dayOfWeek = function(x) {
        return weeks[x];
    };

    var items = ['エアコンの停止', '部屋の電気', '窓の鍵閉め', '玄関の鍵閉め', '電気のブレーカー', 'ガスの元栓', '水道の元栓'];
    if (isEnglish) {
        items = ['Air conditioner stop', 'Room electricity', 'Window lock', 'Lock the entrance', 'Electric breaker', 'Gas tap', 'Water tap'];
    }

    for (var i = 0; i < items.length; i++) {

        // 項目名
        var index = (i + 1).toString();
        $('#lbl' + index + 'a').text(items[i]);

        // チェック状態
        var checked = Cookies.get('chk' + index);
        if (checked == undefined || checked == 'false') {
            checked = false;
        } else {
            checked = true;
        }
        
        $('#chk' + index).prop('checked', checked).change();

        // 更新日
        var updatedAt = Cookies.get('lbl' + index + 'b');
        if (updatedAt == 'undefined') {
            updatedAt = '        ';
        }

        $('#lbl' + index + 'b').text(updatedAt);
        $('#lbl' + index + 'b').css('color', 'gray');

        // イベントの購読。On の場合、更新日時を表示する
        $('#chk' + index).change(function() {
            var now = new Date();
            var d = '' + now.getFullYear() + '/' +
                zeroFormat((now.getMonth() + 1)) + '/' +
                zeroFormat(now.getDate()) + ' ' +
                dayOfWeek(now.getDay()) + ' ' +
                zeroFormat(now.getHours()) + ':' +
                zeroFormat(now.getMinutes()) + ':' +
                zeroFormat(now.getSeconds());

            // コントロール名からナンバーのみ抽出して、対応するラベルにセット
            // (chk1 から 1 のような)
            var index = $(this).prop('id').substr(-1, 1);
            $('#lbl' + index + 'b').text(d);

            // 切り替えるたびに、クッキーに保存
            Cookies.set('chk' + index, $(this).prop('checked'), {expires: 30});
            Cookies.set('lbl' + index + 'b', d, {expires: 30});
        });
        
    }
});

最後に

心配性な方向けのもの(というか自分用というか)なのですが、同じような境遇の方の役に立てれば嬉しいです。最後まで読んでいただき、ありがとうございました。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?