Add help index, req edit pages

This commit is contained in:
Daniel J. Summers 2024-06-27 21:21:48 -04:00
parent adbbf9cf4e
commit 0698c25e80
10 changed files with 514 additions and 180 deletions

View File

@ -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."] ] ]

View File

@ -15,130 +15,93 @@ module Navigation =
/// Top navigation bar /// Top navigation bar
let top m = let top m =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
let menuSpacer = rawText "  " let menuSpacer = rawText "  "
let _dropdown = _class "dropdown-btn" let _dropdown = _class "dropdown-btn"
let leftLinks = [ let leftLinks =
match m.User with [ match m.User with
| Some u -> | Some u ->
li [ _class "dropdown" ] [ li [ _class "dropdown" ] [
a [ _dropdown; _ariaLabel s["Requests"].Value; _title s["Requests"].Value; _roleButton ] [ a [ _dropdown; _ariaLabel s["Requests"].Value; _title s["Requests"].Value; _roleButton ] [
icon "question_answer"; space; locStr s["Requests"]; space; icon "keyboard_arrow_down" icon "question_answer"; space; locStr s["Requests"]; space; icon "keyboard_arrow_down" ]
] div [ _class "dropdown-content"; _roleMenuBar ] [
div [ _class "dropdown-content"; _roleMenuBar ] [ a [ _href "/prayer-requests"; _roleMenuItem ] [
a [ _href "/prayer-requests"; _roleMenuItem ] [ icon "compare_arrows"; menuSpacer; locStr s["Maintain"] ]
icon "compare_arrows"; menuSpacer; locStr s["Maintain"] a [ _href "/prayer-requests/view"; _roleMenuItem ] [
] icon "list"; menuSpacer; locStr s["View List"] ] ] ]
a [ _href "/prayer-requests/view"; _roleMenuItem ] [ li [ _class "dropdown" ] [
icon "list"; menuSpacer; locStr s["View List"] 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 ] [
li [ _class "dropdown" ] [ icon "email"; menuSpacer; locStr s["Maintain Group Members"] ]
a [ _dropdown; _ariaLabel s["Group"].Value; _title s["Group"].Value; _roleButton ] [ a [ _href "/small-group/announcement"; _roleMenuItem ] [
icon "group"; space; locStr s["Group"]; space; icon "keyboard_arrow_down" icon "send"; menuSpacer; locStr s["Send Announcement"] ]
] a [ _href "/small-group/preferences"; _roleMenuItem ] [
div [ _class "dropdown-content"; _roleMenuBar ] [ icon "build"; menuSpacer; locStr s["Change Preferences"] ] ] ]
a [ _href "/small-group/members"; _roleMenuItem ] [ if u.IsAdmin then
icon "email"; menuSpacer; locStr s["Maintain Group Members"] li [ _class "dropdown" ] [
] a [ _dropdown
a [ _href "/small-group/announcement"; _roleMenuItem ] [ _ariaLabel s["Administration"].Value
icon "send"; menuSpacer; locStr s["Send Announcement"] _title s["Administration"].Value
] _roleButton ] [
a [ _href "/small-group/preferences"; _roleMenuItem ] [ icon "settings"; space; locStr s["Administration"]; space; icon "keyboard_arrow_down" ]
icon "build"; menuSpacer; locStr s["Change Preferences"] 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"] ]
if u.IsAdmin then a [ _href "/users"; _roleMenuItem ] [ icon "build"; menuSpacer; locStr s["Users"] ] ] ]
li [ _class "dropdown" ] [ | None ->
a [ _dropdown match m.Group with
_ariaLabel s["Administration"].Value | Some _ ->
_title s["Administration"].Value li [] [
_roleButton ] [ a [ _href "/prayer-requests/view"
icon "settings"; space; locStr s["Administration"]; space; icon "keyboard_arrow_down" _ariaLabel s["View Request List"].Value
] _title s["View Request List"].Value ] [
div [ _class "dropdown-content"; _roleMenuBar ] [ icon "list"; space; locStr s["View Request List"] ] ]
a [ _href "/churches"; _roleMenuItem ] [ icon "home"; menuSpacer; locStr s["Churches"] ] | None ->
a [ _href "/small-groups"; _roleMenuItem ] [ icon "send"; menuSpacer; locStr s["Groups"] ] li [ _class "dropdown" ] [
a [ _href "/users"; _roleMenuItem ] [ icon "build"; menuSpacer; locStr s["Users"] ] 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 ] [
| None -> a [ _href "/user/log-on"; _roleMenuItem ] [ icon "person"; menuSpacer; locStr s["User"] ]
match m.Group with a [ _href "/small-group/log-on"; _roleMenuItem ] [
| Some _ -> icon "group"; menuSpacer; locStr s["Group"] ] ] ]
li [] [ li [] [
a [ _href "/prayer-requests/view" a [ _href "/prayer-requests/lists"
_ariaLabel s["View Request List"].Value _ariaLabel s["View Request List"].Value
_title s["View Request List"].Value ] [ _title s["View Request List"].Value ] [
icon "list"; space; locStr s["View Request List"] icon "list"; space; locStr s["View Request List"] ] ]
] li [] [
] a [ _href "/help"; _ariaLabel s["Help"].Value; _title s["View Help"].Value; _target "_blank" ] [
| None -> icon "help"; space; locStr s["Help"] ] ] ]
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 rightLinks = let rightLinks =
match m.Group with match m.Group with
| Some _ -> | Some _ ->
[ match m.User with [ match m.User with
| Some _ -> | Some _ ->
li [] [ li [] [
a [ _href "/user/password" a [ _href "/user/password"
_ariaLabel s["Change Your Password"].Value _ariaLabel s["Change Your Password"].Value
_title s["Change Your Password"].Value ] [ _title s["Change Your Password"].Value ] [
icon "lock"; space; locStr s["Change Your Password"] icon "lock"; space; locStr s["Change Your Password"] ] ]
] | None -> ()
] li [] [
| None -> () a [ _href "/log-off"; _ariaLabel s["Log Off"].Value; _title s["Log Off"].Value; Target.body ] [
li [] [ icon "power_settings_new"; space; locStr s["Log Off"] ] ] ]
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 -> [] | None -> []
header [ _class "pt-title-bar"; Target.content ] [ header [ _class "pt-title-bar"; Target.content ] [
section [ _class "pt-title-bar-left"; _ariaLabel "Left side of top menu" ] [ section [ _class "pt-title-bar-left"; _ariaLabel "Left side of top menu" ] [
span [ _class "pt-title-bar-home" ] [ span [ _class "pt-title-bar-home" ] [
a [ _href "/"; _title s["Home"].Value ] [ locStr s["PrayerTracker"] ] a [ _href "/"; _title s["Home"].Value ] [ locStr s["PrayerTracker"] ] ]
] ul [] leftLinks ]
ul [] leftLinks
]
section [ _class "pt-title-bar-center"; _ariaLabel "Empty center space in top menu" ] [] 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" ] [ section [ _class "pt-title-bar-right"; _roleToolBar; _ariaLabel "Right side of top menu" ] [
ul [] rightLinks ul [] rightLinks ] ]
]
]
/// Identity bar (below top nav) /// Identity bar (below top nav)
let identity m = let identity m =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
header [ _id "pt-language"; Target.body ] [ header [ _id "pt-language"; Target.body ] [
div [] [ div [] [
span [ _title s["Language"].Value ] [ icon "record_voice_over"; space ] span [ _title s["Language"].Value ] [ icon "record_voice_over"; space ]
@ -150,29 +113,26 @@ module Navigation =
| _ -> | _ ->
strong [] [ locStr s["English"] ] strong [] [ locStr s["English"] ]
rawText "     " 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 match m.Group with
| Some g -> | Some g ->
[ match m.User with [ match m.User with
| Some u -> | Some u ->
span [ _class "u" ] [ locStr s["Currently Logged On"] ] span [ _class "u" ] [ locStr s["Currently Logged On"] ]
rawText "   " rawText "   "
icon "person" icon "person"
strong [] [ str u.Name ] strong [] [ str u.Name ]
rawText "    " rawText "    "
| None -> | None ->
locStr s["Logged On as a Member of"] locStr s["Logged On as a Member of"]
rawText "  " rawText "  "
icon "group" icon "group"
space space
match m.User with match m.User with
| Some _ -> a [ _href "/small-group"; Target.content ] [ strong [] [ str g.Name ] ] | Some _ -> a [ _href "/small-group"; Target.content ] [ strong [] [ str g.Name ] ]
| None -> strong [] [ str g.Name ] | None -> strong [] [ str g.Name ] ]
]
| None -> [] | None -> []
|> div [] |> div [] ]
]
/// Content layouts /// Content layouts
@ -198,7 +158,7 @@ let private commonHead = [
/// Render the <head> portion of the page /// Render the <head> portion of the page
let private htmlHead viewInfo pgTitle = let private htmlHead viewInfo pgTitle =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
head [] [ head [] [
meta [ _charset "UTF-8" ] meta [ _charset "UTF-8" ]
title [] [ locStr pgTitle; titleSep; locStr s["PrayerTracker"] ] 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 /// Render a link to the help page for the current page
let private helpLink link = let private helpLink link =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
sup [ _class "pt-help-link" ] [ sup [ _class "pt-help-link" ] [
a [ _href link a [ _href link
_title s["Click for Help on This Page"].Value _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 /// Render the messages that may need to be displayed to the user
let private messages viewInfo = let private messages viewInfo =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
if List.isEmpty viewInfo.Messages then [] if List.isEmpty viewInfo.Messages then []
else else
viewInfo.Messages viewInfo.Messages
@ -259,70 +219,61 @@ open NodaTime
/// Render the <footer> at the bottom of the page /// Render the <footer> at the bottom of the page
let private htmlFooter viewInfo = let private htmlFooter viewInfo =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
let imgText = $"""%O{s["PrayerTracker"]} %O{s["from Bit Badger Solutions"]}""" let imgText = $"""%O{s["PrayerTracker"]} %O{s["from Bit Badger Solutions"]}"""
let resultTime = (SystemClock.Instance.GetCurrentInstant () - viewInfo.RequestStart).TotalSeconds let resultTime = (SystemClock.Instance.GetCurrentInstant() - viewInfo.RequestStart).TotalSeconds
footer [ _class "pt-footer" ] [ footer [ _class "pt-footer" ] [
div [ _id "pt-legal" ] [ div [ _id "pt-legal" ] [
a [ _href "/legal/privacy-policy" ] [ locStr s["Privacy Policy"] ] a [ _href "/legal/privacy-policy" ] [ locStr s["Privacy Policy"] ]
rawText " &nbsp; " rawText " &nbsp; "
a [ _href "/legal/terms-of-service" ] [ locStr s["Terms of Service"] ] a [ _href "/legal/terms-of-service" ] [ locStr s["Terms of Service"] ]
rawText " &nbsp; " rawText " &nbsp; "
a [ _href "https://github.com/bit-badger/PrayerTracker" a [ _href "https://git.bitbadger.solutions/bit-badger/PrayerTracker"
_title s["View source code and get technical support"].Value _title s["View source code and get technical support"].Value
_target "_blank" _target "_blank"
_relNoOpener ] [ _relNoOpener ] [
locStr s["Source & Support"] locStr s["Source & Support"] ] ]
]
]
div [ _id "pt-footer" ] [ div [ _id "pt-footer" ] [
a [ _href "/"; _style "line-height:28px;" ] [ a [ _href "/"; _style "line-height:28px;" ] [
img [ _src $"""/img/%O{s["footer_en"]}.png""" img [ _src $"""/img/%O{s["footer_en"]}.png"""
_alt imgText _alt imgText
_title imgText _title imgText
_width "331"; _height "28" ] _width "331"; _height "28" ] ]
]
span [ _id "pt-version" ] [ str viewInfo.Version ] span [ _id "pt-version" ] [ str viewInfo.Version ]
space space
i [ _title s["This page loaded in {0:N3} seconds", resultTime].Value; _class "material-icons md-18" ] [ i [ _title s["This page loaded in {0:N3} seconds", resultTime].Value; _class "material-icons md-18" ] [
str "schedule" str "schedule" ] ] ]
]
]
]
/// The content portion of the PrayerTracker layout /// The content portion of the PrayerTracker layout
let private contentSection viewInfo pgTitle (content : XmlNode) = [ let private contentSection viewInfo pgTitle (content: XmlNode) =
Navigation.identity viewInfo [ Navigation.identity viewInfo
renderPageTitle viewInfo pgTitle renderPageTitle viewInfo pgTitle
yield! messages viewInfo yield! messages viewInfo
match viewInfo.ScopedStyle with match viewInfo.ScopedStyle with
| [] -> () | [] -> ()
| styles -> style [] [ rawText (styles |> String.concat " ") ] | styles -> style [] [ rawText (styles |> String.concat " ") ]
content content
htmlFooter viewInfo htmlFooter viewInfo
match viewInfo.OnLoadScript with match viewInfo.OnLoadScript with
| Some onLoad -> | Some onLoad ->
let doCall = if onLoad.EndsWith ")" then "" else "()" let doCall = if onLoad.EndsWith ")" then "" else "()"
script [] [ script [] [
rawText $" rawText $"
window.doOnLoad = () => {{ window.doOnLoad = () => {{
if (window.PT) {{ if (window.PT) {{
{onLoad}{doCall} {onLoad}{doCall}
delete window.doOnLoad delete window.doOnLoad
}} else {{ setTimeout(window.doOnLoad, 500) }} }} else {{ setTimeout(window.doOnLoad, 500) }}
}} }}
window.doOnLoad()" window.doOnLoad()" ]
] | None -> () ]
| None -> ()
]
/// The HTML head element for partial responses /// The HTML head element for partial responses
let private partialHead pgTitle = let private partialHead pgTitle =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
head [] [ head [] [
meta [ _charset "UTF-8" ] meta [ _charset "UTF-8" ]
title [] [ locStr pgTitle; titleSep; locStr s["PrayerTracker"] ] title [] [ locStr pgTitle; titleSep; locStr s["PrayerTracker"] ] ]
]
open Giraffe.Htmx.Common open Giraffe.Htmx.Common
@ -337,12 +288,11 @@ let private pageLayout viewInfo pgTitle content =
Script.minified Script.minified
script [ _src "/js/ckeditor/ckeditor.js" ] [] script [ _src "/js/ckeditor/ckeditor.js" ] []
script [ _src "/js/app.js" ] [] script [ _src "/js/app.js" ] []
| _ -> () | _ -> () ]
]
/// The standard layout(s) for PrayerTracker /// The standard layout(s) for PrayerTracker
let standard viewInfo pageTitle content = let standard viewInfo pageTitle content =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
let pgTitle = s[pageTitle] let pgTitle = s[pageTitle]
html [ _lang (langCode ()) ] [ html [ _lang (langCode ()) ] [
match viewInfo.Layout with match viewInfo.Layout with
@ -354,13 +304,46 @@ let standard viewInfo pageTitle content =
pageLayout viewInfo pgTitle content pageLayout viewInfo pgTitle content
| ContentOnly -> | ContentOnly ->
partialHead pgTitle partialHead pgTitle
body [] (contentSection viewInfo pgTitle content) body [] (contentSection viewInfo pgTitle content) ]
]
/// A layout with nothing but a title and content /// A layout with nothing but a title and content
let bare pageTitle content = let bare pageTitle content =
let s = I18N.localizer.Force () let s = I18N.localizer.Force()
html [ _lang (langCode ()) ] [ html [ _lang (langCode ()) ] [
partialHead s[pageTitle] partialHead s[pageTitle]
body [] [ content ] body [] [ content ] ]
]
/// Help page layout
let help pageTitle isHome content =
let s = I18N.localizer.Force()
let pgTitle = s[pageTitle]
html [ _lang (langCode ()) ] [
head [] [
meta [ _charset "UTF-8" ]
meta [ _name "viewport"; _content "width=device-width, initial-scale=1" ]
title [] [ locStr pgTitle; titleSep; locStr s["PrayerTracker Help"] ]
link [ _href "https://fonts.googleapis.com/icon?family=Material+Icons"; _rel "stylesheet" ]
link [ _href "/css/app.css"; _rel "stylesheet" ]
link [ _href "/css/help.css"; _rel "stylesheet" ] ]
body [] [
header [ _class "pt-title-bar" ] [
section [ _class "pt-title-bar-left" ] [
span [ _class "pt-title-bar-home" ] [
a [ _href "/help"; _title "Home" ] [ locStr s["PrayerTracker"] ] ] ]
section [ _class "pt-title-bar-right" ] [ locStr s["Help"] ] ]
div [ _id "pt-body" ] [
h2 [ _id "pt-page-title" ] [ locStr pgTitle ]
div [ _class "pt-content" ] [
yield! content
div [ _class "pt-close-window" ] [
p [ _class "pt-center-text" ] [
a [ _href "#"; _title s["Click to Close This Window"].Value
_onclick "window.close(); return false" ] [
i [ _class "material-icons"] [ rawText "cancel" ]
space; locStr s["Close Window"] ] ] ]
if not isHome then
div [ _class "pt-help-index" ] [
p [ _class "pt-center-text" ] [
a [ _href "/help"; _title s["Help Index"].Value ] [
rawText "&#xab; "; locStr s["Back to Help Index"] ] ] ] ] ] ] ]

View File

@ -11,6 +11,7 @@
<Compile Include="PrayerRequest.fs" /> <Compile Include="PrayerRequest.fs" />
<Compile Include="SmallGroup.fs" /> <Compile Include="SmallGroup.fs" />
<Compile Include="User.fs" /> <Compile Include="User.fs" />
<Compile Include="Help.fs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -33,6 +34,12 @@
<EmbeddedResource Update="Resources\Common.es.resx"> <EmbeddedResource Update="Resources\Common.es.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Update="Resources\Help\Index.es.resx">
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\Help\Requests\Edit.es.resx">
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\Views\Home\Error.es.resx"> <EmbeddedResource Update="Resources\Views\Home\Error.es.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource> </EmbeddedResource>

View File

@ -882,4 +882,22 @@
<data name="This User Is a {0} Administrator" xml:space="preserve"> <data name="This User Is a {0} Administrator" xml:space="preserve">
<value>Este Usuario Es un Administrador de {0}</value> <value>Este Usuario Es un Administrador de {0}</value>
</data> </data>
<data name="PrayerTracker Help" xml:space="preserve">
<value>Ayuda de SeguidorOración</value>
</data>
<data name="Click to Close This Window" xml:space="preserve">
<value>Haga Clic para Cerrar Esta Ventana</value>
</data>
<data name="Close Window" xml:space="preserve">
<value>Cerrar Esta Ventana</value>
</data>
<data name="Help Index" xml:space="preserve">
<value>Índice de Ayuda</value>
</data>
<data name="Back to Help Index" xml:space="preserve">
<value>Volver al Índice de Ayuda</value>
</data>
<data name="Add / Edit a Request" xml:space="preserve">
<value>Agregar o Editar una Petición</value>
</data>
</root> </root>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Throughout PrayerTracker, you'll see an icon (a question mark in a circle) next to the title on each page." xml:space="preserve">
<value>En todo el sistema, verá un icono (un signo de interrogación en un círculo) junto al título de cada página.</value>
</data>
<data name="Clicking this will open a new, small window with directions on using that page." xml:space="preserve">
<value>Al hacer clic en esta opción, se abrirá una nueva y pequeña ventana con instrucciones sobre cómo usar esa página.</value>
</data>
<data name="If you are looking for a quick overview of PrayerTracker, start with the “Add / Edit a Request” and “Change Preferences” entries." xml:space="preserve">
<value>Si está buscando una descripción rápida de SeguidorOración, comience con las entradas “Agregar o Editar una Petición” y “Cambiar las Preferencias”.</value>
</data>
</root>

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="This page allows you to enter or update a new prayer request." xml:space="preserve">
<value>Esta página le permite introducir o actualizar una petición de oración nueva.</value>
</data>
<data name="There are 5 request types in PrayerTracker." xml:space="preserve">
<value>Hay 5 tipos de peticiones en SeguidorOración.</value>
</data>
<data name="“Current Requests” are your regular requests that people may have regarding things happening over the next week or so." xml:space="preserve">
<value>“Peticiones Actuales” son sus peticiones habituales que la gente pueda tener acerca de las cosas que suceden durante la próxima semana o así.</value>
</data>
<data name="“Long-Term Requests” are requests that may occur repeatedly or continue indefinitely." xml:space="preserve">
<value>“Peticiones a Largo Plazo” son peticiones que pueden ocurrir varias veces, o continuar indefinidamente.</value>
</data>
<data name="“Praise Reports” are like “Current Requests”, but they are answers to prayer to share with your group." xml:space="preserve">
<value>“Informes de Alabanza” son como “Peticiones Actuales”, pero son respuestas a la oración para compartir con su grupo.</value>
</data>
<data name="“Expecting” is for those who are pregnant." xml:space="preserve">
<value>“Embarazada” es para aquellos que están embarazadas.</value>
</data>
<data name="“Announcements” are like “Current Requests”, but instead of a request, they are simply passing information along about something coming up." xml:space="preserve">
<value>“Anuncios” son como “Peticiones Actuales”, pero en lugar de una petición, simplemente se pasa la información a lo largo de algo por venir.</value>
</data>
<data name="The order above is the order in which the request types appear on the list." xml:space="preserve">
<value>El orden anterior es el orden en que los tipos de peticiones aparecen en la lista.</value>
</data>
<data name="“Long-Term Requests” and “Expecting” are not subject to the automatic expiration (set on the “Change Preferences” page) that the other requests are." xml:space="preserve">
<value>“Peticiones a Largo Plazo” y “Embarazada” no están sujetos a la caducidad automática (establecida en el “Cambiar las Preferencias” de la página) que las peticiones son otros.</value>
</data>
<data name="For new requests, this is a box with a calendar date picker." xml:space="preserve">
<value>Para nuevas peticiones, se trata de una caja con un selector de fechas del calendario.</value>
</data>
<data name="Click or tab into the box to display the calendar, which will be preselected to today's date." xml:space="preserve">
<value>Haga clic en la pestaña o en la caja para mostrar el calendario, que será preseleccionada para la fecha de hoy.</value>
</data>
<data name="For existing requests, there will be a check box labeled “Check to not update the date”." xml:space="preserve">
<value>Para peticiones existentes, habrá una casilla de verificación “Seleccionar para no actualizar la fecha”.</value>
</data>
<data name="This can be used if you are correcting spelling or punctuation, and do not have an actual update to make to the request." xml:space="preserve">
<value>Esto puede ser usado si corrige la ortografía ni la puntuacion, y no tienen una actualización real de hacer la petición.</value>
</data>
<data name="For requests or praises, this field is for the name of the person who made the request or offered the praise report." xml:space="preserve">
<value>Para las peticiones o alabanzas, este campo es el nombre de la persona que hizo la petición o que ofrece el informe de alabanza.</value>
</data>
<data name="For announcements, this should contain the subject of the announcement." xml:space="preserve">
<value>Para los anuncios, este debe contener el objeto del anuncio.</value>
</data>
<data name="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." xml:space="preserve">
<value>Para todos los tipos, es opcional, yo solía tener un anuncio con ningún tema que iba todas las semanas, diciendo a dónde enviar peticiones y actualizaciones.</value>
</data>
<data name="“Expire Normally” means that the request is subject to the expiration days in the group preferences." xml:space="preserve">
<value>“Expirará Normalmente” significa que la petición está sujeta a los días de vencimiento de las preferencias del grupo.</value>
</data>
<data name="“Request Never Expires” can be used to make a request never expire (note that this is redundant for “Long-Term Requests” and “Expecting”)." xml:space="preserve">
<value>“Petición no Expira Nunca” se puede utilizar para hacer una petición que no caduque nunca (nótese que esto es redundante para los tipos “Peticiones a Largo Plazo” y “Embarazada”).</value>
</data>
<data name="If you are editing an existing request, a third option appears." xml:space="preserve">
<value>Si está editando una petición existente, aparece una tercera opción.</value>
</data>
<data name="“Expire Immediately” will make the request expire when it is saved." xml:space="preserve">
<value>“Expirará Inmediatamente” hará que la petición expirará cuando se guarda.</value>
</data>
<data name="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." xml:space="preserve">
<value>Aparte de los iconos de la página de mantenimiento de las peticiones, ésta es la única otra forma de expirar peticiones del tipos “Peticiones a Largo Plazo” y “Embarazada”, pero puede ser utilizada para cualquier tipo de petición.</value>
</data>
<data name="This is the text of the request." xml:space="preserve">
<value>Este es el texto de la petición.</value>
</data>
<data name="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." xml:space="preserve">
<value>El editor ofrece muchas capacidades de formato, como "El Corrector Ortográfico al Escribir" (habilitado predeterminado), "Pegar desde Word" y "Pegar sin formato", así como "Código Fuente" punto de vista, si quieres editar el código HTML usted mismo.</value>
</data>
<data name="It also supports undo and redo, and the editor supports full-screen mode. Hover over each icon to see what each button does." xml:space="preserve">
<value>También es compatible con deshacer y rehacer, y el editor soporta modo de pantalla completa. Pase el ratón sobre cada icono para ver qué hace cada botón.</value>
</data>
</root>

View File

@ -98,6 +98,12 @@ module Configure =
] ]
route "/class/logon" (redirectTo true "/small-group/log-on") route "/class/logon" (redirectTo true "/small-group/log-on")
routef "/error/%s" Handlers.Home.error routef "/error/%s" Handlers.Home.error
subRoute "/help" [
route "" Handlers.Help.index
subRoute "/requests" [
route "/edit" Handlers.Help.Requests.edit
]
]
routef "/language/%s" Handlers.Home.language routef "/language/%s" Handlers.Home.language
subRoute "/legal" [ subRoute "/legal" [
route "/privacy-policy" Handlers.Home.privacyPolicy route "/privacy-policy" Handlers.Home.privacyPolicy

24
src/PrayerTracker/Help.fs Normal file
View File

@ -0,0 +1,24 @@
/// Handlers for /help routes
module PrayerTracker.Handlers.Help
open Giraffe
open PrayerTracker
// GET: /help
let index : HttpHandler = fun next ctx -> task {
return!
Views.Help.index ()
|> Views.Layout.help ctx.Strings["Help Index"].Value true
|> renderHtml next ctx
}
/// Handlers for /help/requests routes
module Requests =
// GET: /help/requests/edit
let edit : HttpHandler = fun next ctx -> task {
return!
Views.Help.Requests.edit ()
|> Views.Layout.help ctx.Strings["Add / Edit a Request"].Value false
|> renderHtml next ctx
}

View File

@ -16,6 +16,7 @@
<Compile Include="Email.fs" /> <Compile Include="Email.fs" />
<Compile Include="CommonFunctions.fs" /> <Compile Include="CommonFunctions.fs" />
<Compile Include="Church.fs" /> <Compile Include="Church.fs" />
<Compile Include="Help.fs" />
<Compile Include="Home.fs" /> <Compile Include="Home.fs" />
<Compile Include="PrayerRequest.fs" /> <Compile Include="PrayerRequest.fs" />
<Compile Include="SmallGroup.fs" /> <Compile Include="SmallGroup.fs" />

View File

@ -5,6 +5,9 @@
background-color: white; background-color: white;
padding: 0 .25em; padding: 0 .25em;
} }
.pt-title-bar-home {
height: 2rem;
}
.pt-title-bar-left { .pt-title-bar-left {
color: white; color: white;
font-size: 1.25rem; font-size: 1.25rem;
@ -17,9 +20,24 @@
font-size: 1.1rem; font-size: 1.1rem;
font-variant: small-caps; font-variant: small-caps;
margin-right: 1rem; margin-right: 1rem;
align-self: center;
} }
h2 { h2 {
margin-top: 0; margin-top: 0;
padding-left: .5rem; padding-left: .5rem;
border-bottom: solid 1px #444; border-bottom: solid 1px #444;
} }
.pt-close-window, .pt-help-index {
font-size: 1.25rem;
}
.pt-help-index {
display: none;
}
@media screen and (min-width:451px) {
.pt-close-window {
display: none;
}
.pt-help-index {
display: block;
}
}