From 0698c25e80f4bafe8eff2248b6636d7240e55ea0 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Thu, 27 Jun 2024 21:21:48 -0400 Subject: [PATCH] Add help index, req edit pages --- src/PrayerTracker.UI/Help.fs | 74 ++++ src/PrayerTracker.UI/Layout.fs | 343 +++++++++--------- src/PrayerTracker.UI/PrayerTracker.UI.fsproj | 7 + src/PrayerTracker.UI/Resources/Common.es.resx | 18 + .../Resources/Views/Help/Index.es.resx | 70 ++++ .../Views/Help/Requests/Edit.es.resx | 133 +++++++ src/PrayerTracker/App.fs | 6 + src/PrayerTracker/Help.fs | 24 ++ src/PrayerTracker/PrayerTracker.fsproj | 1 + src/PrayerTracker/wwwroot/css/help.css | 18 + 10 files changed, 514 insertions(+), 180 deletions(-) create mode 100644 src/PrayerTracker.UI/Help.fs create mode 100644 src/PrayerTracker.UI/Resources/Views/Help/Index.es.resx create mode 100644 src/PrayerTracker.UI/Resources/Views/Help/Requests/Edit.es.resx create mode 100644 src/PrayerTracker/Help.fs diff --git a/src/PrayerTracker.UI/Help.fs b/src/PrayerTracker.UI/Help.fs new file mode 100644 index 0000000..054b21a --- /dev/null +++ b/src/PrayerTracker.UI/Help.fs @@ -0,0 +1,74 @@ +/// Help content for PrayerTracker +module PrayerTracker.Views.Help + +open System.IO +open Giraffe.ViewEngine + +/// The help index page +let index () = + let s = I18N.localizer.Force() + let l = I18N.forView "Help/Index" + use sw = new StringWriter() + let raw = rawLocText sw + [ p [] [ + raw l["Throughout PrayerTracker, you'll see an icon (a question mark in a circle) next to the title on each page."]; space + raw l["Clicking this will open a new, small window with directions on using that page."]; space + raw l["If you are looking for a quick overview of PrayerTracker, start with the “Add / Edit a Request” and “Change Preferences” entries."] ] + hr [] + p [ _class "pt-center-text" ] [ strong [] [ locStr s["Help Topics"] ] ] + p [] [ a [ _href "/help/small-group/preferences" ] [ locStr s["Change Preferences"] ] ] + p [] [ a [ _href "/help/small-group/announcement" ] [ locStr s["Send Announcement"] ] ] + p [] [ a [ _href "/help/small-group/members" ] [ locStr s["Maintain Group Members"] ] ] + p [] [ a [ _href "/help/requests/edit" ] [ locStr s["Add / Edit a Request"] ] ] + p [] [ a [ _href "/help/requests/maintain" ] [ locStr s["Maintain Requests"] ] ] + p [] [ a [ _href "/help/requests/view" ] [ locStr s["View Request List"] ] ] + p [] [ a [ _href "/help/user/log-on" ] [ locStr s["Log On"] ] ] + p [] [ a [ _href "/help/user/password" ] [ locStr s["Change Your Password"] ] ] ] + + +/// Help for prayer requests +module Requests = + + /// Add / Edit a Request + let edit () = + let s = I18N.localizer.Force() + let l = I18N.forView "Help/Requests/Edit" + use sw = new StringWriter() + let raw = rawLocText sw + [ p [] [ raw l["This page allows you to enter or update a new prayer request."] ] + h2 [] [ locStr s["Request Type"] ] + p [] [ + raw l["There are 5 request types in PrayerTracker."]; space + raw l["“Current Requests” are your regular requests that people may have regarding things happening over the next week or so."]; space + raw l["“Long-Term Requests” are requests that may occur repeatedly or continue indefinitely."]; space + raw l["“Praise Reports” are like “Current Requests”, but they are answers to prayer to share with your group."]; space + raw l["“Expecting” is for those who are pregnant."]; space + raw l["“Announcements” are like “Current Requests”, but instead of a request, they are simply passing information along about something coming up."] ] + p [] [ + raw l["The order above is the order in which the request types appear on the list."]; space + raw l["“Long-Term Requests” and “Expecting” are not subject to the automatic expiration (set on the “Change Preferences” page) that the other requests are."] ] + h2 [] [ locStr s["Date"] ] + p [] [ + raw l["For new requests, this is a box with a calendar date picker."]; space + raw l["Click or tab into the box to display the calendar, which will be preselected to today's date."]; space + raw l["For existing requests, there will be a check box labeled “Check to not update the date”."]; space + raw l["This can be used if you are correcting spelling or punctuation, and do not have an actual update to make to the request."] + ] + h2 [] [ locStr s["Requestor / Subject"] ] + p [] [ + raw l["For requests or praises, this field is for the name of the person who made the request or offered the praise report."]; space + raw l["For announcements, this should contain the subject of the announcement."]; space + raw l["For all types, it is optional; I used to have an announcement with no subject that ran every week, telling where to send requests and updates."] ] + h2 [] [ locStr s["Expiration"] ] + p [] [ + raw l["“Expire Normally” means that the request is subject to the expiration days in the group preferences."]; space + raw l["“Request Never Expires” can be used to make a request never expire (note that this is redundant for “Long-Term Requests” and “Expecting”)."]; space + raw l["If you are editing an existing request, a third option appears."]; space + raw l["“Expire Immediately” will make the request expire when it is saved."]; space + raw l["Apart from the icons on the request maintenance page, this is the only way to expire “Long-Term Requests” and “Expecting” requests, but it can be used for any request type."] ] + h2 [] [ locStr s["Request"] ] + p [] [ + raw l["This is the text of the request."]; space + raw l["The editor provides many formatting capabilities, including “Spell Check as you Type” (enabled by default), “Paste from Word”, and “Paste Plain”, as well as “Source” view, if you want to edit the HTML yourself."]; space + raw l["It also supports undo and redo, and the editor supports full-screen mode. Hover over each icon to see what each button does."] ] ] + \ No newline at end of file diff --git a/src/PrayerTracker.UI/Layout.fs b/src/PrayerTracker.UI/Layout.fs index e32b3be..556a557 100644 --- a/src/PrayerTracker.UI/Layout.fs +++ b/src/PrayerTracker.UI/Layout.fs @@ -15,130 +15,93 @@ module Navigation = /// Top navigation bar let top m = - let s = I18N.localizer.Force () + let s = I18N.localizer.Force() let menuSpacer = rawText "  " let _dropdown = _class "dropdown-btn" - let leftLinks = [ - match m.User with - | Some u -> - li [ _class "dropdown" ] [ - a [ _dropdown; _ariaLabel s["Requests"].Value; _title s["Requests"].Value; _roleButton ] [ - icon "question_answer"; space; locStr s["Requests"]; space; icon "keyboard_arrow_down" - ] - div [ _class "dropdown-content"; _roleMenuBar ] [ - a [ _href "/prayer-requests"; _roleMenuItem ] [ - icon "compare_arrows"; menuSpacer; locStr s["Maintain"] - ] - a [ _href "/prayer-requests/view"; _roleMenuItem ] [ - icon "list"; menuSpacer; locStr s["View List"] - ] - ] - ] - li [ _class "dropdown" ] [ - a [ _dropdown; _ariaLabel s["Group"].Value; _title s["Group"].Value; _roleButton ] [ - icon "group"; space; locStr s["Group"]; space; icon "keyboard_arrow_down" - ] - div [ _class "dropdown-content"; _roleMenuBar ] [ - a [ _href "/small-group/members"; _roleMenuItem ] [ - icon "email"; menuSpacer; locStr s["Maintain Group Members"] - ] - a [ _href "/small-group/announcement"; _roleMenuItem ] [ - icon "send"; menuSpacer; locStr s["Send Announcement"] - ] - a [ _href "/small-group/preferences"; _roleMenuItem ] [ - icon "build"; menuSpacer; locStr s["Change Preferences"] - ] - ] - ] - if u.IsAdmin then - li [ _class "dropdown" ] [ - a [ _dropdown - _ariaLabel s["Administration"].Value - _title s["Administration"].Value - _roleButton ] [ - icon "settings"; space; locStr s["Administration"]; space; icon "keyboard_arrow_down" - ] - div [ _class "dropdown-content"; _roleMenuBar ] [ - a [ _href "/churches"; _roleMenuItem ] [ icon "home"; menuSpacer; locStr s["Churches"] ] - a [ _href "/small-groups"; _roleMenuItem ] [ icon "send"; menuSpacer; locStr s["Groups"] ] - a [ _href "/users"; _roleMenuItem ] [ icon "build"; menuSpacer; locStr s["Users"] ] - ] - ] - | None -> - match m.Group with - | Some _ -> - li [] [ - a [ _href "/prayer-requests/view" - _ariaLabel s["View Request List"].Value - _title s["View Request List"].Value ] [ - icon "list"; space; locStr s["View Request List"] - ] - ] - | None -> - li [ _class "dropdown" ] [ - a [ _dropdown; _ariaLabel s["Log On"].Value; _title s["Log On"].Value; _roleButton ] [ - icon "security"; space; locStr s["Log On"]; space; icon "keyboard_arrow_down" - ] - div [ _class "dropdown-content"; _roleMenuBar ] [ - a [ _href "/user/log-on"; _roleMenuItem ] [ icon "person"; menuSpacer; locStr s["User"] ] - a [ _href "/small-group/log-on"; _roleMenuItem ] [ - icon "group"; menuSpacer; locStr s["Group"] - ] - ] - ] - li [] [ - a [ _href "/prayer-requests/lists" - _ariaLabel s["View Request List"].Value - _title s["View Request List"].Value ] [ - icon "list"; space; locStr s["View Request List"] - ] - ] - li [] [ - a [ _href $"https://docs.prayer.bitbadger.solutions/{langCode ()}" - _ariaLabel s["Help"].Value - _title s["View Help"].Value - _target "_blank" - _relNoOpener ] [ - icon "help"; space; locStr s["Help"] - ] - ] - ] + let leftLinks = + [ match m.User with + | Some u -> + li [ _class "dropdown" ] [ + a [ _dropdown; _ariaLabel s["Requests"].Value; _title s["Requests"].Value; _roleButton ] [ + icon "question_answer"; space; locStr s["Requests"]; space; icon "keyboard_arrow_down" ] + div [ _class "dropdown-content"; _roleMenuBar ] [ + a [ _href "/prayer-requests"; _roleMenuItem ] [ + icon "compare_arrows"; menuSpacer; locStr s["Maintain"] ] + a [ _href "/prayer-requests/view"; _roleMenuItem ] [ + icon "list"; menuSpacer; locStr s["View List"] ] ] ] + li [ _class "dropdown" ] [ + a [ _dropdown; _ariaLabel s["Group"].Value; _title s["Group"].Value; _roleButton ] [ + icon "group"; space; locStr s["Group"]; space; icon "keyboard_arrow_down" ] + div [ _class "dropdown-content"; _roleMenuBar ] [ + a [ _href "/small-group/members"; _roleMenuItem ] [ + icon "email"; menuSpacer; locStr s["Maintain Group Members"] ] + a [ _href "/small-group/announcement"; _roleMenuItem ] [ + icon "send"; menuSpacer; locStr s["Send Announcement"] ] + a [ _href "/small-group/preferences"; _roleMenuItem ] [ + icon "build"; menuSpacer; locStr s["Change Preferences"] ] ] ] + if u.IsAdmin then + li [ _class "dropdown" ] [ + a [ _dropdown + _ariaLabel s["Administration"].Value + _title s["Administration"].Value + _roleButton ] [ + icon "settings"; space; locStr s["Administration"]; space; icon "keyboard_arrow_down" ] + div [ _class "dropdown-content"; _roleMenuBar ] [ + a [ _href "/churches"; _roleMenuItem ] [ icon "home"; menuSpacer; locStr s["Churches"] ] + a [ _href "/small-groups"; _roleMenuItem ] [ + icon "send"; menuSpacer; locStr s["Groups"] ] + a [ _href "/users"; _roleMenuItem ] [ icon "build"; menuSpacer; locStr s["Users"] ] ] ] + | None -> + match m.Group with + | Some _ -> + li [] [ + a [ _href "/prayer-requests/view" + _ariaLabel s["View Request List"].Value + _title s["View Request List"].Value ] [ + icon "list"; space; locStr s["View Request List"] ] ] + | None -> + li [ _class "dropdown" ] [ + a [ _dropdown; _ariaLabel s["Log On"].Value; _title s["Log On"].Value; _roleButton ] [ + icon "security"; space; locStr s["Log On"]; space; icon "keyboard_arrow_down" ] + div [ _class "dropdown-content"; _roleMenuBar ] [ + a [ _href "/user/log-on"; _roleMenuItem ] [ icon "person"; menuSpacer; locStr s["User"] ] + a [ _href "/small-group/log-on"; _roleMenuItem ] [ + icon "group"; menuSpacer; locStr s["Group"] ] ] ] + li [] [ + a [ _href "/prayer-requests/lists" + _ariaLabel s["View Request List"].Value + _title s["View Request List"].Value ] [ + icon "list"; space; locStr s["View Request List"] ] ] + li [] [ + a [ _href "/help"; _ariaLabel s["Help"].Value; _title s["View Help"].Value; _target "_blank" ] [ + icon "help"; space; locStr s["Help"] ] ] ] let rightLinks = match m.Group with | Some _ -> - [ match m.User with - | Some _ -> - li [] [ - a [ _href "/user/password" - _ariaLabel s["Change Your Password"].Value - _title s["Change Your Password"].Value ] [ - icon "lock"; space; locStr s["Change Your Password"] - ] - ] - | None -> () - li [] [ - a [ _href "/log-off"; _ariaLabel s["Log Off"].Value; _title s["Log Off"].Value; Target.body ] [ - icon "power_settings_new"; space; locStr s["Log Off"] - ] - ] - ] + [ match m.User with + | Some _ -> + li [] [ + a [ _href "/user/password" + _ariaLabel s["Change Your Password"].Value + _title s["Change Your Password"].Value ] [ + icon "lock"; space; locStr s["Change Your Password"] ] ] + | None -> () + li [] [ + a [ _href "/log-off"; _ariaLabel s["Log Off"].Value; _title s["Log Off"].Value; Target.body ] [ + icon "power_settings_new"; space; locStr s["Log Off"] ] ] ] | None -> [] header [ _class "pt-title-bar"; Target.content ] [ section [ _class "pt-title-bar-left"; _ariaLabel "Left side of top menu" ] [ span [ _class "pt-title-bar-home" ] [ - a [ _href "/"; _title s["Home"].Value ] [ locStr s["PrayerTracker"] ] - ] - ul [] leftLinks - ] + a [ _href "/"; _title s["Home"].Value ] [ locStr s["PrayerTracker"] ] ] + ul [] leftLinks ] section [ _class "pt-title-bar-center"; _ariaLabel "Empty center space in top menu" ] [] section [ _class "pt-title-bar-right"; _roleToolBar; _ariaLabel "Right side of top menu" ] [ - ul [] rightLinks - ] - ] + ul [] rightLinks ] ] /// Identity bar (below top nav) let identity m = - let s = I18N.localizer.Force () + let s = I18N.localizer.Force() header [ _id "pt-language"; Target.body ] [ div [] [ span [ _title s["Language"].Value ] [ icon "record_voice_over"; space ] @@ -150,29 +113,26 @@ module Navigation = | _ -> strong [] [ locStr s["English"] ] rawText "     " - a [ _href "/language/es" ] [ locStr s["Cambie a Español"] ] - ] + a [ _href "/language/es" ] [ locStr s["Cambie a Español"] ] ] match m.Group with | Some g -> - [ match m.User with - | Some u -> - span [ _class "u" ] [ locStr s["Currently Logged On"] ] - rawText "   " - icon "person" - strong [] [ str u.Name ] - rawText "    " - | None -> - locStr s["Logged On as a Member of"] - rawText "  " - icon "group" - space - match m.User with - | Some _ -> a [ _href "/small-group"; Target.content ] [ strong [] [ str g.Name ] ] - | None -> strong [] [ str g.Name ] - ] + [ match m.User with + | Some u -> + span [ _class "u" ] [ locStr s["Currently Logged On"] ] + rawText "   " + icon "person" + strong [] [ str u.Name ] + rawText "    " + | None -> + locStr s["Logged On as a Member of"] + rawText "  " + icon "group" + space + match m.User with + | Some _ -> a [ _href "/small-group"; Target.content ] [ strong [] [ str g.Name ] ] + | None -> strong [] [ str g.Name ] ] | None -> [] - |> div [] - ] + |> div [] ] /// Content layouts @@ -198,7 +158,7 @@ let private commonHead = [ /// Render the portion of the page let private htmlHead viewInfo pgTitle = - let s = I18N.localizer.Force () + let s = I18N.localizer.Force() head [] [ meta [ _charset "UTF-8" ] title [] [ locStr pgTitle; titleSep; locStr s["PrayerTracker"] ] @@ -212,7 +172,7 @@ open Giraffe.ViewEngine.Htmx /// Render a link to the help page for the current page let private helpLink link = - let s = I18N.localizer.Force () + let s = I18N.localizer.Force() sup [ _class "pt-help-link" ] [ a [ _href link _title s["Click for Help on This Page"].Value @@ -233,7 +193,7 @@ let private renderPageTitle viewInfo pgTitle = /// Render the messages that may need to be displayed to the user let private messages viewInfo = - let s = I18N.localizer.Force () + let s = I18N.localizer.Force() if List.isEmpty viewInfo.Messages then [] else viewInfo.Messages @@ -259,70 +219,61 @@ open NodaTime /// Render the