Skip to content

Commit

Permalink
Add user list and detail for new admin (#265)
Browse files Browse the repository at this point in the history
* add user list and detail for new admin

* code refactor
  • Loading branch information
zhendi authored Jun 21, 2024
1 parent f46dc83 commit c7092d0
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 0 deletions.
3 changes: 3 additions & 0 deletions app/controllers/internal_api/admin/application_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class InternalApi::Admin::ApplicationController < InternalApi::ApplicationController
before_action :authenticate_admin_user
end
34 changes: 34 additions & 0 deletions app/controllers/internal_api/admin/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class InternalApi::Admin::UsersController < InternalApi::Admin::ApplicationController
before_action :find_user, only: [:show]

def index
if params[:keyword].present?
@users = User.where(
search_columns.map { |column| "#{column} LIKE :keyword" }.join(" OR "),
keyword: "%#{params[:keyword]}%"
).page(params[:page]).per(params[:per])
else
@users = User.all.page(params[:page]).per(params[:per])
end
render json: { users: @users, total_count: @users.total_count }
end

def show
render json: @user.to_json
end

private

def user_params
params.permit(:name, :email, :phone)
end

def find_user
@user = User.find_by(id: params[:id])
return render json: { message: "User not found" }, status: :not_found unless @user
end

def search_columns
%w[name email phone nickname]
end
end
4 changes: 4 additions & 0 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ import AdminNavbar from "./components/new_admin/AdminNavbar.vue"
import AdminMenu from "./components/new_admin/AdminMenu.vue"
import AdminDashboard from "./components/new_admin/AdminDashboard.vue"
import AdminEmailSending from "./components/new_admin/AdminEmailSending.vue"
import AdminUserList from "./components/new_admin/users/AdminUserList.vue"
import AdminUserDetail from "./components/new_admin/users/AdminUserDetail.vue"

const pinia = createPinia()

Expand Down Expand Up @@ -111,6 +113,8 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
const routes = [
{ path: '/new_admin/', component: AdminDashboard },
{ path: '/new_admin/email_sending', component: AdminEmailSending },
{ path: '/new_admin/users', component: AdminUserList },
{ path: '/new_admin/users/:id', component: AdminUserDetail },
]

const router = createRouter({
Expand Down
7 changes: 7 additions & 0 deletions app/javascript/components/new_admin/AdminMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
{{ $t('admin.dashboard.title') }}
</RouterLink>

<RouterLink
to="/new_admin/users"
class="underline"
>
Users
</RouterLink>

<RouterLink
v-if="!onPremise"
to="/new_admin/email_sending"
Expand Down
58 changes: 58 additions & 0 deletions app/javascript/components/new_admin/users/AdminUserDetail.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<template>
<div>
<el-card>
<template #header>
<div class="card-header">
<span>User Detail</span>
</div>
</template>
<ul class="max-w-[480px]">
<li class="flex justify-between mb-4">
<label>Name</label>
<p>{{ user.name }}</p>
</li>
<li class="flex justify-between mb-4">
<label>Nickname</label>
<p>{{ user.nickname }}</p>
</li>
<li class="flex justify-between mb-4">
<label>Phone</label>
<p>{{ user.phone }}</p>
</li>
<li class="flex justify-between mb-4">
<label>Role</label>
<p>{{ user.role }}</p>
</li>
<li class="flex justify-between mb-4">
<label>Created At</label>
<p>{{ dayjs(user.created_at).format('YYYY-MM-DD HH:mm:ss') }}</p>
</li>
</ul>
</el-card>
</div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import dayjs from "dayjs"
import { ElMessage } from 'element-plus'
const route = useRoute()
const user = ref({})
const fetchUser = async () => {
const response = await fetch(`/internal_api/admin/users/${route.params.id}`)
if (response.ok) {
const data = await response.json()
user.value = data
} else {
ElMessage.error('Failed to fetch user')
}
}
onMounted(() => {
fetchUser()
})
</script>
99 changes: 99 additions & 0 deletions app/javascript/components/new_admin/users/AdminUserList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<template>
<div>
<el-card>
<template #header>
<div class="flex items-center justify-between mb-[20px]">
<h3 class="text-[20x] font-[500]">Users</h3>
<el-input
v-model="keyword"
style="width: 240px"
placeholder="Name, Email, Phone"
:prefix-icon="Search"
@input="searchUsers"
/>
</div>
</template>
<el-table
:stripe="true"
:data="users"
style="width: 100%"
>
<el-table-column
prop="name"
label="Name"
/>
<el-table-column
prop="nickname"
label="Nickname"
/>
<el-table-column
prop="email"
label="Email"
/>
<el-table-column
prop="phone"
label="Phone"
/>
<el-table-column label="Operations">
<template #default="scope">
<el-button
size="small"
@click="showDetail(scope.row)"
>
详情
</el-button>
</template>
</el-table-column>
</el-table>

<el-pagination
v-model:current-page="page"
:page-size="per"
layout="prev, pager, next"
:total="total"
@current-change="fetchUsers"
class="my-[52px] flex justify-center"
/>
</el-card>
</div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
const users = ref([])
const page = ref(1)
const per = ref(10)
const total = ref(0)
const keyword = ref('')
const fetchUsers = async (current) => {
const response = await fetch(
`/internal_api/admin/users?page=${current || page.value}&per=${
per.value
}&keyword=${keyword.value}`
)
if (response.ok) {
const data = await response.json()
users.value = data.users
total.value = data.total_count
} else {
ElMessage.error('Failed to fetch users')
}
}
const searchUsers = () => {
page.value = 1
fetchUsers()
}
const showDetail = (row) => {
window.location.href = `/new_admin/users/${row.id}`
}
onMounted(() => {
fetchUsers()
})
</script>
2 changes: 2 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ def as_json options = nil
email: email,
phone: phone,
avatar: avatar_url,
role: roles,
last_login_at: last_login_at,
created_at: created_at
}
end

Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

# internal api
namespace :internal_api do
namespace :admin do
resources :users, only: [:index, :show]
end

resources :organizations, only: [:create, :update] do
collection do
post '/new-members', to: 'organizations#new_members'
Expand Down

0 comments on commit c7092d0

Please sign in to comment.