Search, Paging, and "As of" Date #10
| @ -90,7 +90,7 @@ type AppDbContext with | ||||
|       } | ||||
| 
 | ||||
|   /// Get all (or active) requests for a small group as of now or the specified date | ||||
|   member this.AllRequestsForSmallGroup (grp : SmallGroup) clock listDate activeOnly : PrayerRequest seq = | ||||
|   member this.AllRequestsForSmallGroup (grp : SmallGroup) clock listDate activeOnly pageNbr : PrayerRequest seq = | ||||
|     let theDate = match listDate with Some dt -> dt | _ -> grp.localDateNow clock | ||||
|     upcast ( | ||||
|       this.PrayerRequests.AsNoTracking().Where(fun pr -> pr.smallGroupId = grp.smallGroupId) | ||||
| @ -104,8 +104,13 @@ type AppDbContext with | ||||
|                   || RequestType.Expecting = pr.requestType) | ||||
|               && not pr.isManuallyExpired) | ||||
|       | query -> query | ||||
|       |> reqSort grp.preferences.requestSort) | ||||
| 
 | ||||
|       |> reqSort grp.preferences.requestSort | ||||
|       |> function | ||||
|       | query -> | ||||
|           match activeOnly with | ||||
|           | true -> query.Skip 0 | ||||
|           | false -> query.Skip((pageNbr - 1) * grp.preferences.pageSize).Take grp.preferences.pageSize) | ||||
|        | ||||
|   /// Count prayer requests for the given small group Id | ||||
|   member this.CountRequestsBySmallGroup gId = | ||||
|     this.PrayerRequests.CountAsync (fun pr -> pr.smallGroupId = gId) | ||||
|  | ||||
| @ -1,10 +1,9 @@ | ||||
| module PrayerTracker.Entities.EntitiesTests | ||||
| 
 | ||||
| open Expecto | ||||
| open System | ||||
| open System.Linq | ||||
| open NodaTime.Testing | ||||
| open NodaTime | ||||
| open System | ||||
| 
 | ||||
| [<Tests>] | ||||
| let churchTests = | ||||
| @ -45,6 +44,7 @@ let listPreferencesTests = | ||||
|       Expect.isFalse mt.isPublic "The isPublic flag should not have been set" | ||||
|       Expect.equal mt.timeZoneId "America/Denver" "The default time zone should have been America/Denver" | ||||
|       Expect.equal mt.timeZone.timeZoneId "" "The default preferences should have included an empty time zone" | ||||
|       Expect.equal mt.pageSize 100 "The default page size should have been 100" | ||||
|       } | ||||
|     ] | ||||
| 
 | ||||
|  | ||||
| @ -68,6 +68,21 @@ let htmlToPlainTextTests = | ||||
|       } | ||||
|     ] | ||||
| 
 | ||||
| [<Tests>] | ||||
| let makeUrlTests = | ||||
|   testList "makeUrl" [ | ||||
|     test "returns the URL when there are no parameters" { | ||||
|       Expect.equal (makeUrl "/test" []) "/test" "The URL should not have had any query string parameters added" | ||||
|       } | ||||
|     test "returns the URL with one query string parameter" { | ||||
|       Expect.equal (makeUrl "/test" [ "unit", "true" ]) "/test?unit=true" "The URL was not constructed properly" | ||||
|       } | ||||
|     test "returns the URL with multiple encoded query string parameters" { | ||||
|       let url = makeUrl "/test" [ "space", "a space"; "turkey", "=" ] | ||||
|       Expect.equal url "/test?space=a+space&turkey=%3D" "The URL was not constructed properly" | ||||
|       } | ||||
|     ] | ||||
| 
 | ||||
| [<Tests>] | ||||
| let sndAsStringTests = | ||||
|   testList "sndAsString" [ | ||||
|  | ||||
| @ -438,6 +438,19 @@ let groupLogOnTests = | ||||
|       } | ||||
|     ] | ||||
| 
 | ||||
| [<Tests>] | ||||
| let maintainRequestsTests = | ||||
|   testList "MaintainRequests" [ | ||||
|     test "empty is as expected" { | ||||
|       let mt = MaintainRequests.empty | ||||
|       Expect.isEmpty mt.requests "The requests for the model should have been empty" | ||||
|       Expect.equal mt.smallGroup.smallGroupId Guid.Empty "The small group should have been an empty one" | ||||
|       Expect.isNone mt.onlyActive "The only active flag should have been None" | ||||
|       Expect.isNone mt.searchTerm "The search term should have been None" | ||||
|       Expect.isNone mt.pageNbr "The page number should have been None" | ||||
|       } | ||||
|     ] | ||||
| 
 | ||||
| [<Tests>] | ||||
| let requestListTests = | ||||
|   testList "RequestList" [ | ||||
|  | ||||
| @ -75,7 +75,7 @@ let maintain (churches : Church list) (stats : Map<string, ChurchStats>) ctx vi | ||||
|           |> List.map (fun ch -> | ||||
|               let chId      = flatGuid ch.churchId | ||||
|               let delAction = sprintf "/church/%s/delete" chId | ||||
|               let delPrompt = s.["Are you want to delete this {0}?  This action cannot be undone.", | ||||
|               let delPrompt = s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                                   sprintf "%s (%s)" (s.["Church"].Value.ToLower ()) ch.name] | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
|  | ||||
| @ -160,39 +160,50 @@ let lists (grps : SmallGroup list) vi = | ||||
| 
 | ||||
| 
 | ||||
| /// View for the prayer request maintenance page | ||||
| let maintain (reqs : PrayerRequest seq) (grp : SmallGroup) onlyActive (ctx : HttpContext) vi = | ||||
| let maintain m (ctx : HttpContext) vi = | ||||
|   let s    = I18N.localizer.Force () | ||||
|   let now  = grp.localDateNow (ctx.GetService<IClock> ()) | ||||
|   let l    = I18N.forView "Requests/Maintain" | ||||
|   use sw   = new StringWriter () | ||||
|   let raw  = rawLocText sw | ||||
|   let now  = m.smallGroup.localDateNow (ctx.GetService<IClock> ()) | ||||
|   let typs = ReferenceList.requestTypeList s |> Map.ofList | ||||
|   let updReq (req : PrayerRequest) = | ||||
|     match req.updateRequired now grp.preferences.daysToExpire grp.preferences.longTermUpdateWeeks with | ||||
|     match req.updateRequired now m.smallGroup.preferences.daysToExpire m.smallGroup.preferences.longTermUpdateWeeks with | ||||
|     | true -> "pt-request-update" | ||||
|     | false -> "" | ||||
|     |> _class  | ||||
|   let reqExp (req : PrayerRequest) = | ||||
|     _class (match req.isExpired now grp.preferences.daysToExpire with true -> "pt-request-expired" | false -> "") | ||||
|     _class (match req.isExpired now m.smallGroup.preferences.daysToExpire with true -> "pt-request-expired" | false -> "") | ||||
|   /// Iterate the sequence once, before we render, so we can get the count of it at the top of the table | ||||
|   let requests = | ||||
|     reqs | ||||
|     m.requests | ||||
|     |> Seq.map (fun req -> | ||||
|         let reqId     = flatGuid req.prayerRequestId | ||||
|         let reqText   = Utils.htmlToPlainText req.text | ||||
|         let delAction = sprintf "/prayer-request/%s/delete" reqId | ||||
|         let delPrompt = s.["Are you want to delete this prayer request?  This action cannot be undone.\\n(If the prayer request has been answered, or an event has passed, consider inactivating it instead.)"].Value | ||||
|         let delPrompt = | ||||
|           [ s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                 s.["Prayer Request"].Value.ToLower() ] | ||||
|               .Value | ||||
|             "\\n" | ||||
|             l.["(If the prayer request has been answered, or an event has passed, consider inactivating it instead.)"] | ||||
|               .Value | ||||
|             ] | ||||
|           |> String.concat "" | ||||
|         tr [] [ | ||||
|           td [] [ | ||||
|             yield a [ _href (sprintf "/prayer-request/%s/edit" reqId); _title s.["Edit This Prayer Request"].Value ] | ||||
|             yield a [ _href (sprintf "/prayer-request/%s/edit" reqId); _title l.["Edit This Prayer Request"].Value ] | ||||
|               [ icon "edit" ] | ||||
|             match req.isExpired now grp.preferences.daysToExpire with | ||||
|             match req.isExpired now m.smallGroup.preferences.daysToExpire with | ||||
|             | true -> | ||||
|                 yield a [ _href (sprintf "/prayer-request/%s/restore" reqId) | ||||
|                           _title s.["Restore This Inactive Request"].Value ] | ||||
|                           _title l.["Restore This Inactive Request"].Value ] | ||||
|                   [ icon "visibility" ] | ||||
|             | false -> | ||||
|                 yield a [ _href (sprintf "/prayer-request/%s/expire" reqId) | ||||
|                           _title s.["Expire This Request Immediately"].Value ] | ||||
|                           _title l.["Expire This Request Immediately"].Value ] | ||||
|                   [ icon "visibility_off" ] | ||||
|             yield a [ _href delAction; _title s.["Delete This Request"].Value; | ||||
|             yield a [ _href delAction; _title l.["Delete This Request"].Value; | ||||
|                       _onclick (sprintf "return PT.confirmDelete('%s','%s')" delAction delPrompt) ] | ||||
|               [ icon "delete_forever" ] | ||||
|             ] | ||||
| @ -210,15 +221,25 @@ let maintain (reqs : PrayerRequest seq) (grp : SmallGroup) onlyActive (ctx : Htt | ||||
|           ]) | ||||
|     |> List.ofSeq | ||||
|   [ yield div [ _class "pt-center-text" ] [ | ||||
|       br [] | ||||
|       a [ _href (sprintf "/prayer-request/%s/edit" emptyGuid); _title s.["Add a New Request"].Value ] | ||||
|       yield br [] | ||||
|       yield a [ _href (sprintf "/prayer-request/%s/edit" emptyGuid); _title s.["Add a New Request"].Value ] | ||||
|         [ icon "add_circle"; rawText "  "; locStr s.["Add a New Request"] ] | ||||
|       rawText "       " | ||||
|       a [ _href "/prayer-requests/view"; _title s.["View Prayer Request List"].Value ] | ||||
|       yield rawText "       " | ||||
|       yield a [ _href "/prayer-requests/view"; _title s.["View Prayer Request List"].Value ] | ||||
|         [ icon "list"; rawText "  "; locStr s.["View Prayer Request List"] ] | ||||
|       match m.searchTerm with | ||||
|       | Some _ -> | ||||
|           yield rawText "       " | ||||
|           yield a [ _href "/prayer-requests"; _title l.["Clear Search Criteria"].Value ] | ||||
|             [ icon "highlight_off"; rawText "  "; raw l.["Clear Search Criteria"] ] | ||||
|       | None -> () | ||||
|       ] | ||||
|     yield form [ _action "/prayer-requests"; _method "get"; _class "pt-center-text pt-search-form" ] [ | ||||
|       input [ _type "text"; _name "search"; _placeholder s.["Search requests..."].Value ] | ||||
|       input [ _type "text" | ||||
|               _name "search" | ||||
|               _placeholder l.["Search requests..."].Value | ||||
|               _value (defaultArg m.searchTerm "") | ||||
|               ] | ||||
|       space | ||||
|       submit [] "search" s.["Search"] | ||||
|       ] | ||||
| @ -241,20 +262,41 @@ let maintain (reqs : PrayerRequest seq) (grp : SmallGroup) onlyActive (ctx : Htt | ||||
|           ] | ||||
|     yield div [ _class "pt-center-text" ] [ | ||||
|       yield br [] | ||||
|       match onlyActive with | ||||
|       | true -> | ||||
|           yield locStr s.["Inactive requests are currently not shown"] | ||||
|       match m.onlyActive with | ||||
|       | Some true -> | ||||
|           yield raw l.["Inactive requests are currently not shown"] | ||||
|           yield br [] | ||||
|           yield a [ _href "/prayer-requests/inactive" ] [ locStr s.["Show Inactive Requests"] ] | ||||
|       | false -> | ||||
|           yield locStr s.["Inactive requests are currently shown"] | ||||
|           yield br [] | ||||
|           yield a [ _href "/prayer-requests" ] [ locStr s.["Do Not Show Inactive Requests"] ] | ||||
|           yield a [ _href "/prayer-requests/inactive" ] [ raw l.["Show Inactive Requests"] ] | ||||
|       | _ -> | ||||
|           match Option.isSome m.onlyActive with | ||||
|           | true -> | ||||
|               yield raw l.["Inactive requests are currently shown"] | ||||
|               yield br [] | ||||
|               yield a [ _href "/prayer-requests" ] [ raw l.["Do Not Show Inactive Requests"] ] | ||||
|               yield br [] | ||||
|               yield br [] | ||||
|           | false -> () | ||||
|           let srch = [ match m.searchTerm with Some s -> yield "search", s | None -> () ] | ||||
|           let url  = match m.onlyActive with Some true | None -> "" | _ -> "/inactive" |> sprintf "/prayer-requests%s" | ||||
|           let pg   = defaultArg m.pageNbr 1 | ||||
|           match pg with | ||||
|           | 1 -> () | ||||
|           | _ -> | ||||
|               // button (_type "submit" :: attrs) [ icon ico; rawText "  "; locStr text ] | ||||
|               let withPage = match pg with 2 -> srch | _ -> ("page", string (pg - 1)) :: srch | ||||
|               yield a [ _href (makeUrl url withPage) ] | ||||
|                 [ icon "keyboard_arrow_left"; space; raw l.["Previous Page"] ] | ||||
|           yield rawText "     " | ||||
|           match requests.Length = m.smallGroup.preferences.pageSize with | ||||
|           | true -> | ||||
|               yield a [ _href (makeUrl url (("page", string (pg + 1)) :: srch)) ] | ||||
|                 [ raw l.["Next Page"]; space; icon "keyboard_arrow_right" ] | ||||
|           | false -> () | ||||
|       ] | ||||
|     yield form [ _id "DeleteForm"; _action ""; _method "post" ] [ csrfToken ctx ] | ||||
|     ] | ||||
|   |> Layout.Content.wide | ||||
|   |> Layout.standard vi "Maintain Requests" | ||||
|   |> Layout.standard vi (match m.searchTerm with Some _ -> "Search Results" | None -> "Maintain Requests") | ||||
| 
 | ||||
| 
 | ||||
| /// View for the printable prayer request list | ||||
|  | ||||
| @ -55,6 +55,9 @@ | ||||
|     <EmbeddedResource Update="Resources\Views\Requests\Lists.es.resx"> | ||||
|       <Generator>ResXFileCodeGenerator</Generator> | ||||
|     </EmbeddedResource> | ||||
|     <EmbeddedResource Update="Resources\Views\Requests\Maintain.es.resx"> | ||||
|       <Generator>ResXFileCodeGenerator</Generator> | ||||
|     </EmbeddedResource> | ||||
|     <EmbeddedResource Update="Resources\Views\SmallGroup\Preferences.es.resx"> | ||||
|       <Generator>ResXFileCodeGenerator</Generator> | ||||
|     </EmbeddedResource> | ||||
|  | ||||
| @ -144,8 +144,8 @@ | ||||
|   <data name="Aqua" xml:space="preserve"> | ||||
|     <value>Verde Azulado Brillante</value> | ||||
|   </data> | ||||
|   <data name="Are you want to delete this {0}?  This action cannot be undone." xml:space="preserve"> | ||||
|     <value>¿Está desea eliminar este {0}? Esta acción no se puede deshacer.</value> | ||||
|   <data name="Are you sure you want to delete this {0}?  This action cannot be undone." xml:space="preserve"> | ||||
|     <value>¿Seguro que desea eliminar este {0}? Esta acción no se puede deshacer.</value> | ||||
|   </data> | ||||
|   <data name="Attached PDF" xml:space="preserve"> | ||||
|     <value>PDF Adjunto</value> | ||||
| @ -612,9 +612,6 @@ | ||||
|   <data name="Delete This Group" xml:space="preserve"> | ||||
|     <value>Eliminar Este Grupo</value> | ||||
|   </data> | ||||
|   <data name="Do Not Show Inactive Requests" xml:space="preserve"> | ||||
|     <value>No Muestran las Peticiones Inactivos</value> | ||||
|   </data> | ||||
|   <data name="E-mail" xml:space="preserve"> | ||||
|     <value>Correo Electrónico</value> | ||||
|   </data> | ||||
| @ -633,12 +630,6 @@ | ||||
|   <data name="Group Preferences" xml:space="preserve"> | ||||
|     <value>Las Preferencias del Grupo</value> | ||||
|   </data> | ||||
|   <data name="Inactive requests are currently not shown" xml:space="preserve"> | ||||
|     <value>Peticiones inactivas no se muestra actualmente</value> | ||||
|   </data> | ||||
|   <data name="Inactive requests are currently shown" xml:space="preserve"> | ||||
|     <value>Peticiones inactivas se muestra actualmente</value> | ||||
|   </data> | ||||
|   <data name="Maintain Groups" xml:space="preserve"> | ||||
|     <value>Mantener los Grupos</value> | ||||
|   </data> | ||||
| @ -696,9 +687,6 @@ | ||||
|   <data name="Send Announcement to" xml:space="preserve"> | ||||
|     <value>Enviar anuncio a</value> | ||||
|   </data> | ||||
|   <data name="Show Inactive Requests" xml:space="preserve"> | ||||
|     <value>Muestran las Peticiones Inactivos</value> | ||||
|   </data> | ||||
|   <data name="Sort by Last Updated Date" xml:space="preserve"> | ||||
|     <value>Ordenar por Fecha de Última Actualización</value> | ||||
|   </data> | ||||
| @ -729,15 +717,6 @@ | ||||
|   <data name="Active Requests" xml:space="preserve"> | ||||
|     <value>Peticiones Activas</value> | ||||
|   </data> | ||||
|   <data name="Delete This Request" xml:space="preserve"> | ||||
|     <value>Eliminar esta petición</value> | ||||
|   </data> | ||||
|   <data name="Edit This Prayer Request" xml:space="preserve"> | ||||
|     <value>Editar esta petición de oración</value> | ||||
|   </data> | ||||
|   <data name="Expire This Request Immediately" xml:space="preserve"> | ||||
|     <value>Expirar esta petición de oración de inmediato</value> | ||||
|   </data> | ||||
|   <data name="Maintain Prayer Requests" xml:space="preserve"> | ||||
|     <value>Mantener las Peticiones de Oración</value> | ||||
|   </data> | ||||
| @ -747,9 +726,6 @@ | ||||
|   <data name="Quick Actions" xml:space="preserve"> | ||||
|     <value>Acciones Rápidas</value> | ||||
|   </data> | ||||
|   <data name="Restore This Inactive Request" xml:space="preserve"> | ||||
|     <value>Restaurar esta petición inactiva</value> | ||||
|   </data> | ||||
|   <data name="Save" xml:space="preserve"> | ||||
|     <value>Guardar</value> | ||||
|   </data> | ||||
| @ -822,7 +798,10 @@ | ||||
|   <data name="Search" xml:space="preserve"> | ||||
|     <value>Buscar</value> | ||||
|   </data> | ||||
|   <data name="Search requests..." xml:space="preserve"> | ||||
|     <value>Busca las peticiones...</value> | ||||
|   <data name="Prayer Request" xml:space="preserve"> | ||||
|     <value>Petición de Oración</value> | ||||
|   </data> | ||||
|   <data name="Search Results" xml:space="preserve"> | ||||
|     <value>Resultados de la Búsqueda</value> | ||||
|   </data> | ||||
| </root> | ||||
							
								
								
									
										159
									
								
								src/PrayerTracker.UI/Resources/Views/Requests/Maintain.es.resx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								src/PrayerTracker.UI/Resources/Views/Requests/Maintain.es.resx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,159 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <root> | ||||
|   <!--  | ||||
|     Microsoft ResX Schema  | ||||
|      | ||||
|     Version 2.0 | ||||
|      | ||||
|     The primary goals of this format is to allow a simple XML format  | ||||
|     that is mostly human readable. The generation and parsing of the  | ||||
|     various data types are done through the TypeConverter classes  | ||||
|     associated with the data types. | ||||
|      | ||||
|     Example: | ||||
|      | ||||
|     ... ado.net/XML headers & schema ... | ||||
|     <resheader name="resmimetype">text/microsoft-resx</resheader> | ||||
|     <resheader name="version">2.0</resheader> | ||||
|     <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | ||||
|     <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | ||||
|     <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | ||||
|     <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | ||||
|     <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | ||||
|         <value>[base64 mime encoded serialized .NET Framework object]</value> | ||||
|     </data> | ||||
|     <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | ||||
|         <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | ||||
|         <comment>This is a comment</comment> | ||||
|     </data> | ||||
|                  | ||||
|     There are any number of "resheader" rows that contain simple  | ||||
|     name/value pairs. | ||||
|      | ||||
|     Each data row contains a name, and value. The row also contains a  | ||||
|     type or mimetype. Type corresponds to a .NET class that support  | ||||
|     text/value conversion through the TypeConverter architecture.  | ||||
|     Classes that don't support this are serialized and stored with the  | ||||
|     mimetype set. | ||||
|      | ||||
|     The mimetype is used for serialized objects, and tells the  | ||||
|     ResXResourceReader how to depersist the object. This is currently not  | ||||
|     extensible. For a given mimetype the value must be set accordingly: | ||||
|      | ||||
|     Note - application/x-microsoft.net.object.binary.base64 is the format  | ||||
|     that the ResXResourceWriter will generate, however the reader can  | ||||
|     read any of the formats listed below. | ||||
|      | ||||
|     mimetype: application/x-microsoft.net.object.binary.base64 | ||||
|     value   : The object must be serialized with  | ||||
|             : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | ||||
|             : and then encoded with base64 encoding. | ||||
|      | ||||
|     mimetype: application/x-microsoft.net.object.soap.base64 | ||||
|     value   : The object must be serialized with  | ||||
|             : System.Runtime.Serialization.Formatters.Soap.SoapFormatter | ||||
|             : and then encoded with base64 encoding. | ||||
| 
 | ||||
|     mimetype: application/x-microsoft.net.object.bytearray.base64 | ||||
|     value   : The object must be serialized into a byte array  | ||||
|             : using a System.ComponentModel.TypeConverter | ||||
|             : and then encoded with base64 encoding. | ||||
|     --> | ||||
|   <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="(If the prayer request has been answered, or an event has passed, consider inactivating it instead.)" xml:space="preserve"> | ||||
|     <value>(Si la solicitud de oración ha sido respondida o si un evento ha pasado, considere desactivarla.)</value> | ||||
|   </data> | ||||
|   <data name="Clear Search Criteria" xml:space="preserve"> | ||||
|     <value>Borrar los Criterios de Búsqueda</value> | ||||
|   </data> | ||||
|   <data name="Delete This Request" xml:space="preserve"> | ||||
|     <value>Eliminar esta petición</value> | ||||
|   </data> | ||||
|   <data name="Do Not Show Inactive Requests" xml:space="preserve"> | ||||
|     <value>No Muestran las Peticiones Inactivos</value> | ||||
|   </data> | ||||
|   <data name="Edit This Prayer Request" xml:space="preserve"> | ||||
|     <value>Editar esta petición de oración</value> | ||||
|   </data> | ||||
|   <data name="Expire This Request Immediately" xml:space="preserve"> | ||||
|     <value>Expirar esta petición de oración de inmediato</value> | ||||
|   </data> | ||||
|   <data name="Inactive requests are currently not shown" xml:space="preserve"> | ||||
|     <value>Peticiones inactivas no se muestra actualmente</value> | ||||
|   </data> | ||||
|   <data name="Inactive requests are currently shown" xml:space="preserve"> | ||||
|     <value>Peticiones inactivas se muestra actualmente</value> | ||||
|   </data> | ||||
|   <data name="Next Page" xml:space="preserve"> | ||||
|     <value>Siguiente Página</value> | ||||
|   </data> | ||||
|   <data name="Previous Page" xml:space="preserve"> | ||||
|     <value>Página Anterior</value> | ||||
|   </data> | ||||
|   <data name="Restore This Inactive Request" xml:space="preserve"> | ||||
|     <value>Restaurar esta petición inactiva</value> | ||||
|   </data> | ||||
|   <data name="Search requests..." xml:space="preserve"> | ||||
|     <value>Busca las peticiones...</value> | ||||
|   </data> | ||||
|   <data name="Show Inactive Requests" xml:space="preserve"> | ||||
|     <value>Muestran las Peticiones Inactivos</value> | ||||
|   </data> | ||||
| </root> | ||||
| @ -192,7 +192,7 @@ let maintain (grps : SmallGroup list) ctx vi = | ||||
|           |> List.map (fun g -> | ||||
|               let grpId     = flatGuid g.smallGroupId | ||||
|               let delAction = sprintf "/small-group/%s/delete" grpId | ||||
|               let delPrompt = s.["Are you want to delete this {0}?  This action cannot be undone.", | ||||
|               let delPrompt = s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                                    sprintf "%s (%s)" (s.["Small Group"].Value.ToLower ()) g.name].Value | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
| @ -246,8 +246,10 @@ let members (mbrs : Member list) (emailTyps : Map<string, LocalizedString>) ctx | ||||
|           |> List.map (fun mbr -> | ||||
|               let mbrId     = flatGuid mbr.memberId | ||||
|               let delAction = sprintf "/small-group/member/%s/delete" mbrId | ||||
|               let delPrompt = s.["Are you want to delete this {0} ({1})?  This action cannot be undone.", | ||||
|                                   s.["group member"], mbr.memberName].Value | ||||
|               let delPrompt = | ||||
|                 s.["Are you sure you want to delete this {0}?  This action cannot be undone.", s.["group member"]] | ||||
|                   .Value | ||||
|                   .Replace("?", sprintf " (%s)?" mbr.memberName) | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
|                   a [ _href (sprintf "/small-group/member/%s/edit" mbrId); _title s.["Edit This Group Member"].Value ] | ||||
|  | ||||
| @ -190,7 +190,7 @@ let maintain (users : User list) ctx vi = | ||||
|           |> List.map (fun user -> | ||||
|               let userId    = flatGuid user.userId | ||||
|               let delAction = sprintf "/user/%s/delete" userId | ||||
|               let delPrompt = s.["Are you want to delete this {0}?  This action cannot be undone.", | ||||
|               let delPrompt = s.["Are you sure you want to delete this {0}?  This action cannot be undone.", | ||||
|                                   (sprintf "%s (%s)" (s.["User"].Value.ToLower()) user.fullName)].Value | ||||
|               tr [] [ | ||||
|                 td [] [ | ||||
|  | ||||
| @ -127,6 +127,20 @@ let htmlToPlainText html = | ||||
| /// Get the second portion of a tuple as a string | ||||
| let sndAsString x = (snd >> string) x | ||||
| 
 | ||||
| 
 | ||||
| /// Make a URL with query string parameters | ||||
| let makeUrl (url : string) (qs : (string * string) list) = | ||||
|   let queryString = | ||||
|     qs | ||||
|     |> List.fold | ||||
|         (fun (acc : StringBuilder) (key, value) -> | ||||
|             acc.Append(key).Append("=").Append(WebUtility.UrlEncode value).Append "&") | ||||
|         (StringBuilder ()) | ||||
|   match queryString.Length with | ||||
|   | 0 -> url | ||||
|   | _ -> queryString.Insert(0, "?").Insert(0, url).Remove(queryString.Length - 1, 1).ToString () | ||||
| 
 | ||||
| 
 | ||||
| /// "Magic string" repository | ||||
| [<RequireQualifiedAccess>] | ||||
| module Key = | ||||
|  | ||||
| @ -473,7 +473,32 @@ with | ||||
|       } | ||||
| 
 | ||||
| 
 | ||||
| /// Items needed to display the request maintenance page | ||||
| [<NoComparison; NoEquality>] | ||||
| type MaintainRequests = | ||||
|   { /// The requests to be displayed | ||||
|     requests   : PrayerRequest seq | ||||
|     /// The small group to which the requests belong | ||||
|     smallGroup : SmallGroup | ||||
|     /// Whether only active requests are included | ||||
|     onlyActive : bool option | ||||
|     /// The search term for the requests | ||||
|     searchTerm : string option | ||||
|     /// The page number of the results | ||||
|     pageNbr    : int option | ||||
|     } | ||||
| with | ||||
|   static member empty = | ||||
|     { requests   = Seq.empty | ||||
|       smallGroup = SmallGroup.empty  | ||||
|       onlyActive = None | ||||
|       searchTerm = None | ||||
|       pageNbr    = None | ||||
|       } | ||||
| 
 | ||||
| 
 | ||||
| /// Items needed to display the small group overview page | ||||
| [<NoComparison; NoEquality>] | ||||
| type Overview = | ||||
|   { /// The total number of active requests | ||||
|     totalActiveReqs : int | ||||
|  | ||||
| @ -31,7 +31,7 @@ let private generateRequestList ctx date = | ||||
|     match date with | ||||
|     | Some d -> d | ||||
|     | None -> grp.localDateNow clock | ||||
|   let reqs = ctx.dbContext().AllRequestsForSmallGroup grp clock (Some listDate) true | ||||
|   let reqs = ctx.dbContext().AllRequestsForSmallGroup grp clock (Some listDate) true 0 | ||||
|   { requests   = reqs |> List.ofSeq | ||||
|     date       = listDate | ||||
|     listGroup  = grp | ||||
| @ -155,7 +155,7 @@ let list groupId : HttpHandler = | ||||
|       match grp with | ||||
|       | Some g when g.preferences.isPublic -> | ||||
|           let clock = ctx.GetService<IClock> () | ||||
|           let reqs  = db.AllRequestsForSmallGroup g clock None true | ||||
|           let reqs  = db.AllRequestsForSmallGroup g clock None true 0 | ||||
|           return! | ||||
|             viewInfo ctx startTicks | ||||
|             |> Views.PrayerRequest.list | ||||
| @ -199,13 +199,27 @@ let maintain onlyActive : HttpHandler = | ||||
|     let db         = ctx.dbContext () | ||||
|     let grp        = currentGroup ctx | ||||
|     task { | ||||
|       let reqs =  | ||||
|       let pageNbr = | ||||
|         match ctx.GetQueryStringValue "page" with | ||||
|         | Ok pg -> match Int32.TryParse pg with true, p -> p | false, _ -> 1 | ||||
|         | Error _ -> 1 | ||||
|       let m =  | ||||
|         match ctx.GetQueryStringValue "search" with | ||||
|         | Ok srch -> db.SearchRequestsForSmallGroup grp srch 1 | ||||
|         | Error _ -> db.AllRequestsForSmallGroup grp (ctx.GetService<IClock> ()) None onlyActive | ||||
|         | Ok srch -> | ||||
|             { MaintainRequests.empty with | ||||
|                 requests   = db.SearchRequestsForSmallGroup grp srch pageNbr | ||||
|                 searchTerm = Some srch | ||||
|                 pageNbr    = Some pageNbr | ||||
|               } | ||||
|         | Error _ -> | ||||
|             { MaintainRequests.empty with | ||||
|                 requests   = db.AllRequestsForSmallGroup grp (ctx.GetService<IClock> ()) None onlyActive pageNbr | ||||
|                 onlyActive = Some onlyActive | ||||
|                 pageNbr    = match onlyActive with true -> None | false -> Some pageNbr | ||||
|               } | ||||
|       return! | ||||
|         { viewInfo ctx startTicks with helpLink = Some Help.maintainRequests } | ||||
|         |> Views.PrayerRequest.maintain reqs grp onlyActive ctx | ||||
|         |> Views.PrayerRequest.maintain { m with smallGroup = grp } ctx | ||||
|         |> renderHtml next ctx | ||||
|       } | ||||
| 
 | ||||
|  | ||||
| @ -208,7 +208,7 @@ let overview : HttpHandler = | ||||
|     let db         = ctx.dbContext () | ||||
|     let clock      = ctx.GetService<IClock> () | ||||
|     task { | ||||
|       let  reqs     = db.AllRequestsForSmallGroup  (currentGroup ctx) clock None true |> List.ofSeq | ||||
|       let  reqs     = db.AllRequestsForSmallGroup  (currentGroup ctx) clock None true 0 |> List.ofSeq | ||||
|       let! reqCount = db.CountRequestsBySmallGroup (currentGroup ctx).smallGroupId | ||||
|       let! mbrCount = db.CountMembersForSmallGroup (currentGroup ctx).smallGroupId | ||||
|       let m = | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user