Employee files
Add, edit employee (staff and admin)
This commit is contained in:
@@ -0,0 +1,74 @@
|
|||||||
|
package com.example.petstoremobile.adapters;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.view.*;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import com.example.petstoremobile.R;
|
||||||
|
import com.example.petstoremobile.dtos.EmployeeDTO;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class EmployeeAdapter extends RecyclerView.Adapter<EmployeeAdapter.EmployeeViewHolder> {
|
||||||
|
|
||||||
|
private List<EmployeeDTO> list;
|
||||||
|
private OnEmployeeClickListener listener;
|
||||||
|
|
||||||
|
public interface OnEmployeeClickListener {
|
||||||
|
void onEmployeeClick(int position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmployeeAdapter(List<EmployeeDTO> list, OnEmployeeClickListener listener) {
|
||||||
|
this.list = list;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EmployeeViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView tvFullName, tvUsername, tvEmail, tvPhone, tvRole, tvStatus;
|
||||||
|
|
||||||
|
public EmployeeViewHolder(@NonNull View v) {
|
||||||
|
super(v);
|
||||||
|
tvFullName = v.findViewById(R.id.tvEmployeeFullName);
|
||||||
|
tvUsername = v.findViewById(R.id.tvEmployeeUsername);
|
||||||
|
tvEmail = v.findViewById(R.id.tvEmployeeEmail);
|
||||||
|
tvPhone = v.findViewById(R.id.tvEmployeePhone);
|
||||||
|
tvRole = v.findViewById(R.id.tvEmployeeRole);
|
||||||
|
tvStatus = v.findViewById(R.id.tvEmployeeStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public EmployeeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View v = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.item_employee, parent, false);
|
||||||
|
return new EmployeeViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull EmployeeViewHolder holder, int position) {
|
||||||
|
EmployeeDTO e = list.get(position);
|
||||||
|
|
||||||
|
holder.tvFullName.setText(e.getFullName() != null ? e.getFullName() : "");
|
||||||
|
holder.tvUsername.setText("@" + (e.getUsername() != null ? e.getUsername() : ""));
|
||||||
|
holder.tvEmail.setText(e.getEmail() != null ? e.getEmail() : "");
|
||||||
|
holder.tvPhone.setText(e.getPhone() != null ? e.getPhone() : "");
|
||||||
|
|
||||||
|
// Role badge
|
||||||
|
String role = e.getRole() != null ? e.getRole() : "";
|
||||||
|
holder.tvRole.setText(role);
|
||||||
|
holder.tvRole.setBackgroundColor(
|
||||||
|
"ADMIN".equals(role) ? Color.parseColor("#1a759f") : Color.parseColor("#577590"));
|
||||||
|
|
||||||
|
// Status badge
|
||||||
|
boolean active = Boolean.TRUE.equals(e.getActive());
|
||||||
|
holder.tvStatus.setText(active ? "Active" : "Inactive");
|
||||||
|
holder.tvStatus.setBackgroundColor(
|
||||||
|
active ? Color.parseColor("#4CAF50") : Color.parseColor("#F44336"));
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener(v -> listener.onEmployeeClick(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() { return list.size(); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.example.petstoremobile.api;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.EmployeeDTO;
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.*;
|
||||||
|
|
||||||
|
public interface EmployeeApi {
|
||||||
|
|
||||||
|
@GET("api/v1/employees")
|
||||||
|
Call<PageResponse<EmployeeDTO>> getAllEmployees(
|
||||||
|
@Query("page") int page,
|
||||||
|
@Query("size") int size);
|
||||||
|
|
||||||
|
@GET("api/v1/employees/{id}")
|
||||||
|
Call<EmployeeDTO> getEmployeeById(@Path("id") Long id);
|
||||||
|
|
||||||
|
@POST("api/v1/employees")
|
||||||
|
Call<EmployeeDTO> createEmployee(@Body EmployeeDTO employee);
|
||||||
|
|
||||||
|
@PUT("api/v1/employees/{id}")
|
||||||
|
Call<EmployeeDTO> updateEmployee(@Path("id") Long id, @Body EmployeeDTO employee);
|
||||||
|
|
||||||
|
@DELETE("api/v1/employees/{id}")
|
||||||
|
Call<Void> deleteEmployee(@Path("id") Long id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
public class EmployeeDTO {
|
||||||
|
|
||||||
|
private long EmployeeId;
|
||||||
|
private Long userId;
|
||||||
|
private String username;
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
private String fullName;
|
||||||
|
private String email;
|
||||||
|
private String phone;
|
||||||
|
private String role;
|
||||||
|
private Boolean active;
|
||||||
|
private String createAt;
|
||||||
|
private String updatedAt;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor for create and update the employee
|
||||||
|
|
||||||
|
|
||||||
|
public EmployeeDTO(String username, String password, String firstName, String lastName,
|
||||||
|
String email, String phone, String role, boolean active) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.firstName = firstName;
|
||||||
|
this.lastName = lastName;
|
||||||
|
this.email = email;
|
||||||
|
this.phone = phone;
|
||||||
|
this.role = role;
|
||||||
|
this.active = active;
|
||||||
|
}
|
||||||
|
// password field for request only
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
|
||||||
|
public long getEmployeeId() {
|
||||||
|
|
||||||
|
return EmployeeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUserId() {
|
||||||
|
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullName() {
|
||||||
|
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
public String getPhone() {
|
||||||
|
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getActive() {
|
||||||
|
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreateAt() {
|
||||||
|
|
||||||
|
return createAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUpdatedAt() {
|
||||||
|
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package com.example.petstoremobile.fragments.listfragments;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.*;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.*;
|
||||||
|
import android.widget.*;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
import com.example.petstoremobile.R;
|
||||||
|
import com.example.petstoremobile.adapters.EmployeeAdapter;
|
||||||
|
import com.example.petstoremobile.api.RetrofitClient;
|
||||||
|
import com.example.petstoremobile.dtos.EmployeeDTO;
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
|
import com.example.petstoremobile.fragments.listfragments.detailfragments.StaffDetailFragment;
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
import java.util.*;
|
||||||
|
import retrofit2.*;
|
||||||
|
|
||||||
|
public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmployeeClickListener {
|
||||||
|
|
||||||
|
private List<EmployeeDTO> employeeList = new ArrayList<>();
|
||||||
|
private List<EmployeeDTO> filteredList = new ArrayList<>();
|
||||||
|
private EmployeeAdapter adapter;
|
||||||
|
private SwipeRefreshLayout swipeRefresh;
|
||||||
|
private EditText etSearch;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_staff, container, false);
|
||||||
|
|
||||||
|
setupRecyclerView(view);
|
||||||
|
setupSearch(view);
|
||||||
|
setupSwipeRefresh(view);
|
||||||
|
loadStaff();
|
||||||
|
|
||||||
|
FloatingActionButton fab = view.findViewById(R.id.fabAddStaff);
|
||||||
|
fab.setOnClickListener(v -> openDetail(-1));
|
||||||
|
|
||||||
|
ImageButton hamburger = view.findViewById(R.id.btnHamburgerStaff);
|
||||||
|
hamburger.setOnClickListener(v -> {
|
||||||
|
ListFragment lf = (ListFragment) getParentFragment();
|
||||||
|
if (lf != null) lf.openDrawer();
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRecyclerView(View view) {
|
||||||
|
RecyclerView rv = view.findViewById(R.id.recyclerViewStaff);
|
||||||
|
adapter = new EmployeeAdapter(filteredList, this);
|
||||||
|
rv.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
rv.setAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSearch(View view) {
|
||||||
|
etSearch = view.findViewById(R.id.etSearchStaff);
|
||||||
|
etSearch.addTextChangedListener(new TextWatcher() {
|
||||||
|
public void beforeTextChanged(CharSequence s, int a, int b, int c) {}
|
||||||
|
public void afterTextChanged(Editable s) {}
|
||||||
|
public void onTextChanged(CharSequence s, int a, int b, int c) {
|
||||||
|
filter(s.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSwipeRefresh(View view) {
|
||||||
|
swipeRefresh = view.findViewById(R.id.swipeRefreshStaff);
|
||||||
|
swipeRefresh.setOnRefreshListener(this::loadStaff);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void filter(String query) {
|
||||||
|
filteredList.clear();
|
||||||
|
if (query.isEmpty()) {
|
||||||
|
filteredList.addAll(employeeList);
|
||||||
|
} else {
|
||||||
|
String lower = query.toLowerCase();
|
||||||
|
for (EmployeeDTO e : employeeList) {
|
||||||
|
if ((e.getFullName() != null && e.getFullName().toLowerCase().contains(lower))
|
||||||
|
|| (e.getUsername() != null && e.getUsername().toLowerCase().contains(lower))
|
||||||
|
|| (e.getEmail() != null && e.getEmail().toLowerCase().contains(lower))
|
||||||
|
|| (e.getPhone() != null && e.getPhone().toLowerCase().contains(lower))) {
|
||||||
|
filteredList.add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadStaff() {
|
||||||
|
if (swipeRefresh != null) swipeRefresh.setRefreshing(true);
|
||||||
|
RetrofitClient.getEmployeeApi(requireContext()).getAllEmployees(0, 100)
|
||||||
|
.enqueue(new Callback<PageResponse<EmployeeDTO>>() {
|
||||||
|
public void onResponse(Call<PageResponse<EmployeeDTO>> c,
|
||||||
|
Response<PageResponse<EmployeeDTO>> r) {
|
||||||
|
if (swipeRefresh != null) swipeRefresh.setRefreshing(false);
|
||||||
|
if (r.isSuccessful() && r.body() != null) {
|
||||||
|
employeeList.clear();
|
||||||
|
employeeList.addAll(r.body().getContent());
|
||||||
|
filter(etSearch != null ? etSearch.getText().toString() : "");
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), "Failed to load staff",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onFailure(Call<PageResponse<EmployeeDTO>> c, Throwable t) {
|
||||||
|
if (swipeRefresh != null) swipeRefresh.setRefreshing(false);
|
||||||
|
Log.e("StaffFragment", t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openDetail(int position) {
|
||||||
|
StaffDetailFragment detail = new StaffDetailFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
if (position != -1) {
|
||||||
|
EmployeeDTO e = filteredList.get(position);
|
||||||
|
args.putLong("employeeId", e.getEmployeeId());
|
||||||
|
args.putString("username", e.getUsername() != null ? e.getUsername() : "");
|
||||||
|
args.putString("firstName", e.getFirstName() != null ? e.getFirstName() : "");
|
||||||
|
args.putString("lastName", e.getLastName() != null ? e.getLastName() : "");
|
||||||
|
args.putString("email", e.getEmail() != null ? e.getEmail() : "");
|
||||||
|
args.putString("phone", e.getPhone() != null ? e.getPhone() : "");
|
||||||
|
args.putString("role", e.getRole() != null ? e.getRole() : "STAFF");
|
||||||
|
args.putBoolean("active", Boolean.TRUE.equals(e.getActive()));
|
||||||
|
args.putBoolean("isEditing", true);
|
||||||
|
}
|
||||||
|
detail.setArguments(args);
|
||||||
|
ListFragment lf = (ListFragment) getParentFragment();
|
||||||
|
if (lf != null) lf.loadFragment(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEmployeeClick(int position) {
|
||||||
|
openDetail(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
package com.example.petstoremobile.fragments.listfragments.detailfragments;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.*;
|
||||||
|
import android.widget.*;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import com.example.petstoremobile.R;
|
||||||
|
import com.example.petstoremobile.api.EmployeeApi;
|
||||||
|
import com.example.petstoremobile.api.RetrofitClient;
|
||||||
|
import com.example.petstoremobile.dtos.EmployeeDTO;
|
||||||
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
|
import retrofit2.*;
|
||||||
|
|
||||||
|
public class StaffDetailFragment extends Fragment {
|
||||||
|
|
||||||
|
private TextView tvMode, tvStaffId;
|
||||||
|
private EditText etUsername, etPassword, etFirstName, etLastName, etEmail, etPhone;
|
||||||
|
private Spinner spinnerRole, spinnerStatus;
|
||||||
|
private Button btnSave, btnDelete, btnBack;
|
||||||
|
|
||||||
|
private long employeeId = -1;
|
||||||
|
private boolean isEditing = false;
|
||||||
|
|
||||||
|
private final String[] ROLES = {"STAFF", "ADMIN"};
|
||||||
|
private final String[] STATUSES = {"Active", "Inactive"};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_staff_detail, container, false);
|
||||||
|
initViews(view);
|
||||||
|
setupSpinners();
|
||||||
|
handleArguments();
|
||||||
|
|
||||||
|
btnBack.setOnClickListener(v -> navigateBack());
|
||||||
|
btnSave.setOnClickListener(v -> save());
|
||||||
|
btnDelete.setOnClickListener(v -> confirmDelete());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initViews(View v) {
|
||||||
|
tvMode = v.findViewById(R.id.tvStaffMode);
|
||||||
|
tvStaffId = v.findViewById(R.id.tvStaffId);
|
||||||
|
etUsername = v.findViewById(R.id.etStaffUsername);
|
||||||
|
etPassword = v.findViewById(R.id.etStaffPassword);
|
||||||
|
etFirstName = v.findViewById(R.id.etStaffFirstName);
|
||||||
|
etLastName = v.findViewById(R.id.etStaffLastName);
|
||||||
|
etEmail = v.findViewById(R.id.etStaffEmail);
|
||||||
|
etPhone = v.findViewById(R.id.etStaffPhone);
|
||||||
|
spinnerRole = v.findViewById(R.id.spinnerStaffRole);
|
||||||
|
spinnerStatus = v.findViewById(R.id.spinnerStaffStatus);
|
||||||
|
btnSave = v.findViewById(R.id.btnSaveStaff);
|
||||||
|
btnDelete = v.findViewById(R.id.btnDeleteStaff);
|
||||||
|
btnBack = v.findViewById(R.id.btnStaffBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSpinners() {
|
||||||
|
spinnerRole.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item, ROLES));
|
||||||
|
spinnerStatus.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item, STATUSES));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleArguments() {
|
||||||
|
Bundle a = getArguments();
|
||||||
|
if (a != null && a.getBoolean("isEditing", false)) {
|
||||||
|
isEditing = true;
|
||||||
|
employeeId = a.getLong("employeeId", -1);
|
||||||
|
|
||||||
|
tvMode.setText("Edit Staff Account");
|
||||||
|
tvStaffId.setText("ID: " + employeeId);
|
||||||
|
tvStaffId.setVisibility(View.VISIBLE);
|
||||||
|
etUsername.setText(a.getString("username", ""));
|
||||||
|
etFirstName.setText(a.getString("firstName", ""));
|
||||||
|
etLastName.setText(a.getString("lastName", ""));
|
||||||
|
etEmail.setText(a.getString("email", "")); // ← was showing fullName
|
||||||
|
etPhone.setText(a.getString("phone", ""));
|
||||||
|
btnDelete.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
// Pre-fill role
|
||||||
|
String role = a.getString("role", "STAFF");
|
||||||
|
for (int i = 0; i < ROLES.length; i++) {
|
||||||
|
if (ROLES[i].equals(role)) {
|
||||||
|
spinnerRole.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-fill status
|
||||||
|
boolean active = a.getBoolean("active", true);
|
||||||
|
spinnerStatus.setSelection(active ? 0 : 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
isEditing = false;
|
||||||
|
employeeId = -1;
|
||||||
|
tvMode.setText("Add Staff Account");
|
||||||
|
btnDelete.setVisibility(View.GONE);
|
||||||
|
tvStaffId.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
String username = etUsername.getText() != null ? etUsername.getText().toString().trim() : "";
|
||||||
|
String password = etPassword.getText() != null ? etPassword.getText().toString().trim() : "";
|
||||||
|
String firstName = etFirstName.getText() != null ? etFirstName.getText().toString().trim() : "";
|
||||||
|
String lastName = etLastName.getText() != null ? etLastName.getText().toString().trim() : "";
|
||||||
|
String email = etEmail.getText() != null ? etEmail.getText().toString().trim() : "";
|
||||||
|
String phone = etPhone.getText() != null ? etPhone.getText().toString().trim() : "";
|
||||||
|
String role = ROLES[spinnerRole.getSelectedItemPosition()];
|
||||||
|
boolean active = spinnerStatus.getSelectedItemPosition() == 0;
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
if (username.isEmpty()) { etUsername.setError("Required"); return; }
|
||||||
|
if (!isEditing && password.isEmpty()) {
|
||||||
|
etPassword.setError("Required for new account"); return;
|
||||||
|
}
|
||||||
|
if (!isEditing && password.length() < 6) {
|
||||||
|
etPassword.setError("At least 6 characters"); return;
|
||||||
|
}
|
||||||
|
if (firstName.isEmpty()) { etFirstName.setError("Required"); return; }
|
||||||
|
if (lastName.isEmpty()) { etLastName.setError("Required"); return; }
|
||||||
|
if (email.isEmpty()) { etEmail.setError("Required"); return; }
|
||||||
|
if (phone.isEmpty()) { etPhone.setError("Required"); return; }
|
||||||
|
|
||||||
|
EmployeeDTO dto = new EmployeeDTO(
|
||||||
|
username,
|
||||||
|
password.isEmpty() ? null : password,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
email,
|
||||||
|
phone,
|
||||||
|
role,
|
||||||
|
active
|
||||||
|
);
|
||||||
|
|
||||||
|
Log.d("STAFF_SAVE", "isEditing=" + isEditing
|
||||||
|
+ " employeeId=" + employeeId
|
||||||
|
+ " username=" + username);
|
||||||
|
|
||||||
|
EmployeeApi api = RetrofitClient.getEmployeeApi(requireContext());
|
||||||
|
if (isEditing && employeeId > 0) {
|
||||||
|
api.updateEmployee(employeeId, dto).enqueue(simpleCallback("Updated successfully"));
|
||||||
|
} else {
|
||||||
|
api.createEmployee(dto).enqueue(simpleCallback("Staff account created"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Callback<EmployeeDTO> simpleCallback(String msg) {
|
||||||
|
return new Callback<>() {
|
||||||
|
public void onResponse(Call<EmployeeDTO> c, Response<EmployeeDTO> r) {
|
||||||
|
Log.d("STAFF_SAVE", "Response: " + r.code());
|
||||||
|
if (r.isSuccessful()) {
|
||||||
|
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
|
||||||
|
navigateBack();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
String err = r.errorBody().string();
|
||||||
|
Log.e("STAFF_SAVE", "Error: " + err);
|
||||||
|
Toast.makeText(getContext(), "Error " + r.code() + ": " + err,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("STAFF_SAVE", "Failed to read error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onFailure(Call<EmployeeDTO> c, Throwable t) {
|
||||||
|
Log.e("STAFF_SAVE", "Failure: " + t.getMessage());
|
||||||
|
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void confirmDelete() {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle("Delete Staff Account?")
|
||||||
|
.setMessage("This will permanently delete this staff account.")
|
||||||
|
.setPositiveButton("Yes", (d, w) ->
|
||||||
|
RetrofitClient.getEmployeeApi(requireContext())
|
||||||
|
.deleteEmployee(employeeId)
|
||||||
|
.enqueue(new Callback<Void>() {
|
||||||
|
public void onResponse(Call<Void> c, Response<Void> r) {
|
||||||
|
navigateBack();
|
||||||
|
}
|
||||||
|
public void onFailure(Call<Void> c, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Delete failed",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.setNegativeButton("No", null).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateBack() {
|
||||||
|
ListFragment lf = (ListFragment) getParentFragment();
|
||||||
|
if (lf != null) lf.getChildFragmentManager().popBackStack();
|
||||||
|
}
|
||||||
|
}
|
||||||
233
android/app/src/main/res/layout/fragment_staff_detail.xml
Normal file
233
android/app/src/main/res/layout/fragment_staff_detail.xml
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background_grey">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:background="@color/primary_dark"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStaffMode"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Add Staff Account"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnDeleteStaff"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:backgroundTint="@color/accent_coral"
|
||||||
|
android:text="Delete"
|
||||||
|
android:textColor="@color/white"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@drawable/rounded_card"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStaffId"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/text_light"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textStyle="italic"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<!-- Username -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Username"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etStaffUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Enter username"
|
||||||
|
android:inputType="text"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<!-- Password -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Password"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etStaffPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Enter password (leave blank to keep current)"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<!-- First Name -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="First Name"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etStaffFirstName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Enter first name"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<!-- Last Name -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Last Name"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etStaffLastName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Enter last name"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Email"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etStaffEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Enter email"
|
||||||
|
android:inputType="textEmailAddress"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<!-- Phone -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Phone"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etStaffPhone"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Enter phone number"
|
||||||
|
android:inputType="phone"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<!-- Role -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Role"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerStaffRole"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<!-- Status -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Status"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerStaffStatus"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnStaffBack"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="Back"
|
||||||
|
android:backgroundTint="@color/primary_medium"
|
||||||
|
android:textColor="@color/white"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnSaveStaff"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="Save"
|
||||||
|
android:backgroundTint="@color/accent_coral"
|
||||||
|
android:textColor="@color/white"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
99
android/app/src/main/res/layout/item_employee.xml
Normal file
99
android/app/src/main/res/layout/item_employee.xml
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="2dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmployeeFullName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/text_dark"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmployeeUsername"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="@color/text_light"
|
||||||
|
android:layout_marginTop="2dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmployeeEmail"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="@color/text_light"
|
||||||
|
android:layout_marginTop="2dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmployeePhone"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="@color/text_light"
|
||||||
|
android:layout_marginTop="2dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="end"
|
||||||
|
android:layout_gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmployeeRole"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvEmployeeStatus"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="@color/white"/>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
Reference in New Issue
Block a user