Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions app/assets/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#nav {
margin-bottom: 30px;
display: flex;
justify-content: space-between;
align-items: center;
}

#nav ul {
display: flex;
justify-content: end;
align-items: center;
column-gap: 20px;
font-size: 16px;
}
3 changes: 3 additions & 0 deletions app/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
escape_output_instead_of_sanitize: true
---
6 changes: 6 additions & 0 deletions app/graphql/contacts/delete.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
mutation delete($id: ID!) {
record_delete(
table: "contact"
id: $id
){ id }
}
25 changes: 25 additions & 0 deletions app/graphql/contacts/search.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
query contacts_search($page: Int = 1, $per_page: Int = 20, $keyword: String) {
records(
page: $page
per_page: $per_page
filter: {
table: { value: "contact" }
or: [
{ properties: [ { name: "email", contains: $keyword } ] }
{ properties: [ { name: "body", contains: $keyword } ] }
]
}
sort: [{
id: { order: DESC }
}]
) {
total_pages
results {
id
body: property(name: "body")
email: property(name: "email")
created_at
}
}
}

1 change: 0 additions & 1 deletion app/lib/commands/contacts/create.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
function object = 'commands/contacts/create/execute', object: object
assign event_object = '{}' | parse_json | hash_merge: id: object.id
hash_assign event_object["email"] = object.email
log event_object, type: 'event object'
function _ = 'modules/core/commands/events/publish', type: 'contact_created', object: event_object, delay: null, max_attempts: null
endif

Expand Down
9 changes: 9 additions & 0 deletions app/lib/commands/contacts/delete.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% liquid
graphql r = 'contacts/delete', id: id
assign object = r.record_delete

assign event_object = '{}' | parse_json | hash_merge: id: id
function _ = 'modules/core/commands/events/publish', type: 'contact_deleted', object: event_object, delay: null, max_attempts: null

return object
%}
12 changes: 12 additions & 0 deletions app/lib/events/contact_deleted.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
metadata:
event:
id
---
{% liquid
assign c = '{ "errors": {}, "valid": true }' | parse_json

function c = 'modules/core/validations/presence', c: c, object: event, field_name: 'id'

return c
%}
9 changes: 9 additions & 0 deletions app/lib/queries/contacts/search.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% liquid
assign limit = limit | default: 20
assign page = params.page | to_positive_integer: 1
assign keyword = params.keyword | default: null

graphql res = 'contacts/search', per_page: limit, page: page, keyword: keyword

return res.records
%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% parse_json data %}
{
"anonymous": ["sessions.create", "users.register"],
"authenticated": ["sessions.destroy","oauth.manage"],
"admin": ["admin_pages.view", "contacts.manage", "admin.users.manage", "users.impersonate"],
"member": ["profile.manage"],
"superadmin": ["users.impersonate_superadmin"]
}
{% endparse_json %}

{% return data %}
5 changes: 3 additions & 2 deletions app/pos-modules.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"modules": {
"core": "1.5.2",
"common-styling": "1.29.0"
"core": "2.0.7",
"common-styling": "1.32.0",
"user": "5.1.1"
}
}
5 changes: 3 additions & 2 deletions app/pos-modules.lock.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"modules": {
"core": "1.5.2",
"common-styling": "1.29.0"
"core": "2.0.7",
"common-styling": "1.32.0",
"user": "5.1.1"
}
}
13 changes: 11 additions & 2 deletions app/views/layouts/application.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@

{% render 'modules/common-styling/init', reset: true %}
<link rel="stylesheet" href="{{ 'variables.css' | asset_url }}">
<link rel="stylesheet" href="{{ 'app.css' | asset_url }}">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes">
</head>
<body>
{{ content_for_layout }}
{% render 'layout/nav' %}

<div class="container">
{{ content_for_layout }}
</div>

{% liquid
theme_render_rc 'modules/common-styling/toasts'
function flash = 'modules/core/commands/session/get', key: 'sflash', clear: null
if context.location.pathname != flash.from or flash.force_clear
function _ = 'modules/core/commands/session/clear', key: 'sflash'
endif
render 'modules/common-styling/toasts', params: flash
%}
</body>
</html>
17 changes: 17 additions & 0 deletions app/views/pages/admin/contacts/delete.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
slug: admin/contacts/:id
method: delete
---
{% liquid
function current_profile = 'modules/user/helpers/current_profile'
# platformos-check-disable ConvertIncludeToRender, UnreachableCode

include 'modules/user/helpers/can_do_or_unauthorized', requester: current_profile, do: 'contacts.manage', redirect_anonymous_to_login: true, forbidden_partial: '403'
# platformos-check-enable ConvertIncludeToRender, UnreachableCode

function _ = 'commands/contacts/delete', id: context.params.id

render 'modules/core/helpers/flash/publish', notice: 'Contact has been successfully deleted', error: null, info: null
include 'modules/core/helpers/redirect_to', url: '/admin'
%}

12 changes: 12 additions & 0 deletions app/views/pages/admin/index.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% liquid
function current_profile = 'modules/user/helpers/current_profile'
# platformos-check-disable ConvertIncludeToRender, UnreachableCode

include 'modules/user/helpers/can_do_or_unauthorized', requester: current_profile, do: 'admin_pages.view', redirect_anonymous_to_login: true, forbidden_partial: '403'
# platformos-check-enable ConvertIncludeToRender, UnreachableCode

function contacts = 'queries/contacts/search', limit: 10, params: context.params

render 'admin/index', contacts: contacts
%}

12 changes: 5 additions & 7 deletions app/views/pages/index.html.liquid
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{% parse_json contact %}
{
"email": "email@example.com",
"body": "Write your message here"
}
{% endparse_json %}
{% render 'contacts/form', contact: contact %}
{% liquid
function profile = 'modules/user/helpers/current_profile'

render 'contacts/form', contact: null
%}
1 change: 1 addition & 0 deletions app/views/partials/403.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p class="pos-card">You are not authorized to see this page.</p>
55 changes: 55 additions & 0 deletions app/views/partials/admin/index.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<div class="pos-card">
<form method="GET" >
<fieldset class="pos-form-fieldset-combined">
<input type="text" name="keyword" placeholder="Search" class="pos-form-input" value="{{ context.params.keyword }}">
<button type="submit" class="pos-button">
<span class="pos-label">Search</span>
{% render 'modules/common-styling/icon', icon: 'search' %}
</button>
</fieldset>
</form>
</div>
<h1 class="pos-heading-1">Contacts</h1>
<section class="pos-table">
<header>
<div>ID</div>
<div>Email</div>
<div>Body</div>
<div>Created At</div>
<div></div>
</header>
<div class="pos-table-content pos-card">
{% for contact in contacts.results %}
<ul>
<li>
<span class="pos-table-content-heading">ID</span>
{{ contact.id }}
</li>
<li>
<span class="pos-table-content-heading">Email</span>
{{ contact.email }}
</li>
<li>
<span class="pos-table-content-heading">Body</span>
<span title="{{ contact.body }}">{{ contact.body | truncate: 40 }}</span>
</li>
<li>
<span class="pos-table-content-heading">Created At</span>
{{ contact.created_at | to_time | l: 'long' }}
</li>
<li>
<form method="post" action="/admin/contacts/{{ contact.id }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
<input type="hidden" name="authenticity_token" value="{{ context.authenticity_token }}">
<input type="hidden" name="_method" value="delete">
<button class="pos-button" type="submit">
<span class="pos-label">Delete</span>
{% render 'modules/common-styling/icon', icon: 'delete' %}
</button>
</form>
{% if contact.deleted_at %}({{ contact.deleted_at | to_time | l: 'long' }}){% endif %}
</li>
</ul>
{% endfor %}
</div>
</section>
{% render 'modules/common-styling/pagination', total_pages: contacts.total_pages %}
29 changes: 29 additions & 0 deletions app/views/partials/layout/nav.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{% liquid
if context.current_user
assign current_profile = context.exports.current_profile
unless current_profile
function current_profile = 'modules/user/helpers/current_profile'
endunless
endif
%}
<nav id="nav">
<a href="/">Home</a>
<ul>
<li>
{% if current_profile %}
<li>Welcome, {{ current_profile.email }}</li>
{% function can_view_admin = 'modules/user/helpers/can_do', requester: current_profile, do: 'admin_pages.view', access_callback: null, entity: null %}
{% if can_view_admin %}
<li><a href="/admin">Admin</a></li>
{% endif %}
<form method="post" action="/sessions">
<input type="hidden" name="authenticity_token" value="{{ context.authenticity_token }}">
<input type="hidden" name="_method" value="delete">
<button class="pos-button" type="submit">Logout</button>
</form>
{% else %}
<a href="/sessions/new">Login</a>
{% endif %}
</li>
</ul>
</nav>
87 changes: 87 additions & 0 deletions modules/common-styling/public/assets/js/pos-dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
handles openind and closing the dialog box

usage:
*/



// purpose: opens and closes the dialog box
// arguments:
// ************************************************************************
window.pos.modules.dialog = function(userSettings){

// cache 'this' value not to be overwritten later
const module = this;

// purpose: settings that are being used across the module
// ------------------------------------------------------------------------
module.settings = {};
// dialog container (dom node)
module.settings.container = userSettings.container;
// modal trigger (dom node)
module.settings.trigger = userSettings.trigger;
// id used to mark the module (string)
module.settings.id = userSettings.id || module.settings.trigger.dataset.dialogtarget;
// close button (dom nodes)
module.settings.closeButtons = userSettings.closeButtons || module.settings.container?.querySelectorAll('.pos-dialog-close');
// to enable debug mode (bool)
module.settings.debug = (userSettings?.debug) ? userSettings.debug : false;



// purpose: initializes the component
// ------------------------------------------------------------------------
module.init = () => {
pos.modules.debug(module.settings.debug, module.settings.id, 'Initializing dialog', module.settings);

if(!module.settings.container){
console.error('Could not find dialog container with ID ' + module.settings.id + ' while it\'s trigger is present', module.settings.trigger);
}

module.settings.trigger.addEventListener('click', event => {
event.preventDefault();

module.open();
});

module.settings.container?.addEventListener('toggle', event => {
if(event.newState === 'open'){
pos.modules.debug(module.settings.debug, module.settings.id, 'Dialog opened', module.settings.container);
document.dispatchEvent(new CustomEvent('pos-dialog-opened', { bubbles: true, detail: { target: module.settings.container, id: module.settings.id } }));
pos.modules.debug(module.settings.debug, 'event', 'pos-dialog-opened', { target: module.settings.container, id: module.settings.id });
} else if(event.newState === 'closed') {
pos.modules.debug(module.settings.debug, module.settings.id, 'Dialog closed', module.settings.container);
document.dispatchEvent(new CustomEvent('pos-dialog-closed', { bubbles: true, detail: { target: module.settings.container, id: module.settings.id } }));
pos.modules.debug(module.settings.debug, 'event', 'pos-dialog-closed', { target: module.settings.container, id: module.settings.id });
}
});
};


// purpose: opens the dialog
// ------------------------------------------------------------------------
module.open = () => {
module.settings.container.showModal();

module.settings.closeButtons.forEach(button => {
button.addEventListener('click', module.close);
});
};


// purpose: closes the dialog
// ------------------------------------------------------------------------
module.close = () => {
module.settings.closeButtons.forEach(button => {
button.addEventListener('click', module.close);
})

module.settings.container.close();
}



module.init();

};
Loading